diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc776d30a0..48937e2874 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,12 +34,12 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1 + uses: microsoft/setup-msbuild@v1.1 - name: Build Windows working-directory: ${{ env.GITHUB_WORKSPACE }} @@ -63,20 +63,20 @@ jobs: run: cp Windows/Release/*.exe ppsspp/ - name: Upload build - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: name: Windows ${{ matrix.platform }} build path: ppsspp/ build-uwp: - runs-on: windows-latest + runs-on: windows-2019 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1 + uses: microsoft/setup-msbuild@v1.1 - name: Build UWP working-directory: ${{ env.GITHUB_WORKSPACE }} @@ -87,7 +87,7 @@ jobs: needs: build-windows timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: false @@ -97,7 +97,7 @@ jobs: run: git submodule update --init pspautotests assets/lang - name: Download build - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: Windows x64 build path: ppsspp/ @@ -151,6 +151,18 @@ jobs: cxx: clang++ args: cd android && ./ab.sh -j2 APP_ABI=x86_64 UNITTEST=1 HEADLESS=1 id: android-x86_64 + - os: ubuntu-latest + extra: android + cc: clang + cxx: clang++ + args: cd android && ./ab.sh -j2 APP_ABI=arm64-v8a OPENXR=1 OPENXR_PLATFORM_QUEST=1 + id: android-vr-quest + - os: ubuntu-latest + extra: android + cc: clang + cxx: clang++ + args: cd android && ./ab.sh -j2 APP_ABI=arm64-v8a OPENXR=1 OPENXR_PLATFORM_PICO=1 + id: android-vr-pico - os: ubuntu-latest extra: android cc: clang @@ -168,13 +180,13 @@ jobs: extra: libretro cc: gcc cxx: g++ - args: ./b.sh --libretro + args: make -C libretro -f Makefile -j2 id: gcc-libretro - os: ubuntu-latest extra: libretro cc: clang cxx: clang++ - args: ./b.sh --libretro + args: make -C libretro -f Makefile -j2 id: clang-libretro - os: macos-latest @@ -192,7 +204,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive @@ -202,19 +214,11 @@ jobs: run: | git fetch --deepen=15000 --no-recurse-submodules --tags || exit 0 - - name: Cache Qt - uses: actions/cache@v1 - if: matrix.extra == 'qt' - id: cache-qt - with: - path: ${{ runner.workspace }}/Qt - key: ${{ runner.os }}-QtCache - - name: Install Qt - uses: jurplel/install-qt-action@v2 + uses: jurplel/install-qt-action@v3 if: matrix.extra == 'qt' with: - cached: ${{ steps.cache-qt.outputs.cache-hit }} + cache: true - uses: nttld/setup-ndk@v1 if: matrix.extra == 'android' @@ -236,7 +240,7 @@ jobs: echo "#define PPSSPP_GIT_VERSION_NO_UPDATE 1" >> git-version.cpp - name: Setup ccache - uses: hendrikmuhs/ccache-action@v1 + uses: hendrikmuhs/ccache-action@v1.2 with: key: ${{ matrix.id }} @@ -246,8 +250,20 @@ jobs: CXX: ${{ matrix.cxx }} NDK: ${{ steps.setup-ndk.outputs.ndk-path }} NDK_CCACHE: ccache + USE_CCACHE: 1 run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + export CCACHE_SLOPPINESS=clang_index_store,ivfsoverlay,include_file_ctime,include_file_mtime,modules,system_headers,time_macros + if [ "${{ matrix.extra }}" == "android" ]; then + export CCACHE_FILECLONE=true + export CCACHE_DEPEND=true + export CCACHE_COMPILERCHECK=content + elif [ "$RUNNER_OS" == "macOS" ]; then + export CCACHE_SLOPPINESS=pch_defines,$CCACHE_SLOPPINESS + export CCACHE_FILECLONE=true + export CCACHE_DEPEND=true + export CCACHE_COMPILERCHECK=content + fi ${{ matrix.args }} - name: Package build @@ -279,7 +295,7 @@ jobs: fi - name: Upload build - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 if: matrix.extra == 'test' with: name: ${{ matrix.os }} build @@ -313,7 +329,7 @@ jobs: needs: build timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: false @@ -335,7 +351,7 @@ jobs: git submodule update --init SDL/macOS - name: Download build - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: ${{ matrix.os }} build path: ppsspp/ diff --git a/.github/workflows/generateDockerLayer.yml b/.github/workflows/generateDockerLayer.yml index 91164f5af8..5e038f398f 100644 --- a/.github/workflows/generateDockerLayer.yml +++ b/.github/workflows/generateDockerLayer.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Extract DOCKER_TAG using tag name if: startsWith(github.ref, 'refs/tags/') @@ -25,13 +25,13 @@ jobs: echo "DOCKER_TAG=latest" >> $GITHUB_ENV - name: Login to Github registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - - uses: docker/build-push-action@v2 + - uses: docker/build-push-action@v3 with: push: true - tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_TAG }} \ No newline at end of file + tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_TAG }} diff --git a/.github/workflows/manual_generate_apk.yml b/.github/workflows/manual_generate_apk.yml index 3f38055ac5..4c48320259 100644 --- a/.github/workflows/manual_generate_apk.yml +++ b/.github/workflows/manual_generate_apk.yml @@ -19,14 +19,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 submodules: recursive - name: Setup JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: 'zulu' java-version: '11' #- name: Setup SDK @@ -54,7 +55,7 @@ jobs: fi - name: Upload APK - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: name: android-${{ github.event.inputs.buildVariant }} build path: ppsspp/ diff --git a/.github/workflows/tarball.yml b/.github/workflows/tarball.yml index 47c022593e..84fec3625a 100644 --- a/.github/workflows/tarball.yml +++ b/.github/workflows/tarball.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive @@ -40,7 +40,7 @@ jobs: sed -i "s;unknown;${VERSION};" $PKGNAME/git-version.cmake || true TARBALL=$PKGNAME.tar.xz tar cJf $TARBALL $PKGNAME - echo "::set-output name=tarball::$TARBALL" + echo "tarball=$TARBALL" >> $GITHUB_OUTPUT - name: upload tarball uses: softprops/action-gh-release@v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ce455b8a..90cd57ace1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,7 +119,6 @@ add_definitions(-DASSETS_DIR="${CMAKE_INSTALL_FULL_DATADIR}/ppsspp/assets/") if(OPENXR) add_definitions(-DOPENXR) add_library(openxr SHARED IMPORTED) - include_directories(ext/openxr) if(OPENXR_PLATFORM_PICO) add_definitions(-DOPENXR_PLATFORM_PICO) set_property(TARGET openxr PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so") @@ -507,6 +506,24 @@ if(WIN32) ) endif() +set(CommonVR + Common/VR/OpenXRLoader.cpp + Common/VR/OpenXRLoader.h + Common/VR/PPSSPPVR.cpp + Common/VR/PPSSPPVR.h + Common/VR/VRBase.cpp + Common/VR/VRBase.h + Common/VR/VRFramebuffer.cpp + Common/VR/VRFramebuffer.h + Common/VR/VRInput.cpp + Common/VR/VRInput.h + Common/VR/VRMath.cpp + Common/VR/VRMath.h + Common/VR/VRRenderer.cpp + Common/VR/VRRenderer.h +) +include_directories(ext/openxr) + add_library(Common STATIC ${CommonX86} ${CommonARM} @@ -514,6 +531,7 @@ add_library(Common STATIC ${CommonMIPS} ${CommonRISCV64} ${CommonD3D} + ${CommonVR} Common/Serialize/Serializer.cpp Common/Serialize/Serializer.h Common/Serialize/SerializeDeque.h @@ -588,6 +606,7 @@ add_library(Common STATIC Common/File/FileDescriptor.cpp Common/File/FileDescriptor.h Common/GPU/DataFormat.h + Common/GPU/MiscTypes.h Common/GPU/thin3d.cpp Common/GPU/thin3d.h Common/GPU/thin3d_create.h @@ -619,6 +638,8 @@ add_library(Common STATIC Common/GPU/Vulkan/VulkanDebug.h Common/GPU/Vulkan/VulkanContext.cpp Common/GPU/Vulkan/VulkanContext.h + Common/GPU/Vulkan/VulkanFramebuffer.cpp + Common/GPU/Vulkan/VulkanFramebuffer.h Common/GPU/Vulkan/VulkanImage.cpp Common/GPU/Vulkan/VulkanImage.h Common/GPU/Vulkan/VulkanLoader.cpp @@ -674,6 +695,8 @@ add_library(Common STATIC Common/Render/TextureAtlas.h Common/Render/DrawBuffer.cpp Common/Render/DrawBuffer.h + Common/Render/ManagedTexture.cpp + Common/Render/ManagedTexture.h Common/Render/Text/draw_text.cpp Common/Render/Text/draw_text.h Common/Render/Text/draw_text_android.cpp @@ -692,6 +715,8 @@ add_library(Common STATIC Common/Thread/ThreadUtil.h Common/Thread/ThreadManager.cpp Common/Thread/ThreadManager.h + Common/UI/AsyncImageFileView.cpp + Common/UI/AsyncImageFileView.h Common/UI/Root.cpp Common/UI/Root.h Common/UI/Screen.cpp @@ -859,7 +884,7 @@ add_library(cityhash STATIC ext/cityhash/city.h ext/cityhash/citycrc.h ) -include_directories(ext/cityhash) +target_include_directories(cityhash PRIVATE ext/cityhash) if(NOT MSVC) # These can be fast even for debug. @@ -1091,24 +1116,7 @@ if(ANDROID) android/jni/OpenSLContext.cpp android/jni/OpenSLContext.h ) - if (OPENXR) - set(nativeExtra ${nativeExtra} - Common/VR/PPSSPPVR.cpp - Common/VR/PPSSPPVR.h - Common/VR/VRBase.cpp - Common/VR/VRBase.h - Common/VR/VRFramebuffer.cpp - Common/VR/VRFramebuffer.h - Common/VR/VRInput.cpp - Common/VR/VRInput.h - Common/VR/VRMath.cpp - Common/VR/VRMath.h - Common/VR/VRRenderer.cpp - Common/VR/VRRenderer.h - Common/VR/VRTweaks.cpp - Common/VR/VRTweaks.h - ) set(nativeExtraLibs ${nativeExtraLibs} openxr) endif() # No target @@ -1242,8 +1250,6 @@ list(APPEND NativeAppSource UI/ChatScreen.cpp UI/DevScreens.cpp UI/DevScreens.h - UI/DisplayLayoutEditor.cpp - UI/DisplayLayoutEditor.h UI/DisplayLayoutScreen.cpp UI/DisplayLayoutScreen.h UI/EmuScreen.h @@ -1292,8 +1298,6 @@ list(APPEND NativeAppSource UI/MemStickScreen.cpp UI/ProfilerDraw.h UI/ProfilerDraw.cpp - UI/TextureUtil.h - UI/TextureUtil.cpp UI/ComboKeyMappingScreen.h UI/ComboKeyMappingScreen.cpp UI/Theme.h @@ -1312,6 +1316,10 @@ if(ANDROID) endif() endif() +if (IOS) + set(nativeExtra ${nativeExtra} ${NativeAppSource}) +endif() + add_library(native STATIC ${nativeExtra} Common/Render/Text/draw_text_qt.cpp @@ -1356,7 +1364,7 @@ add_library(kirk STATIC ext/libkirk/kirk_engine.c ext/libkirk/kirk_engine.h ) -include_directories(ext/libkirk) +target_include_directories(kirk PRIVATE ext/libkirk) add_library(sfmt19937 STATIC ext/sfmt19937/SFMT.c @@ -1365,19 +1373,20 @@ add_library(sfmt19937 STATIC ext/sfmt19937/SFMT-params.h ext/sfmt19937/SFMT-params19937.h ) -include_directories(ext/sfmt19937) +target_compile_definitions(sfmt19937 PRIVATE SFMT_MEXP=19937) +target_include_directories(sfmt19937 PRIVATE ext/sfmt19937) add_library(xbrz STATIC ext/xbrz/xbrz.cpp ext/xbrz/xbrz.h ) -include_directories(ext/xbrz) +target_include_directories(xbrz PRIVATE ext/xbrz) add_library(xxhash STATIC ext/xxhash.c ext/xxhash.h ) -include_directories(ext/xxhash) +target_include_directories(xxhash PRIVATE ext/xxhash) set(CoreExtra) set(CoreExtraLibs) @@ -2063,6 +2072,7 @@ if(USE_SYSTEM_ZSTD) target_link_libraries(${CoreLibName} ${ZSTD_LIBRARY}) else() set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "we don't need zstd programs" FORCE) + set(ZSTD_LEGACY_SUPPORT OFF CACHE BOOL "we don't use any old zstd files" FORCE) add_subdirectory(ext/zstd/build/cmake EXCLUDE_FROM_ALL) set(CoreExtraLibs ${CoreExtraLibs} libzstd_static) include_directories(ext/zstd/lib) diff --git a/Common/Arm64Emitter.h b/Common/Arm64Emitter.h index 66add4e269..aaeb24fb1d 100644 --- a/Common/Arm64Emitter.h +++ b/Common/Arm64Emitter.h @@ -253,7 +253,7 @@ public: private: ARM64Reg m_destReg; WidthSpecifier m_width; - ExtendSpecifier m_extend; + ExtendSpecifier m_extend = EXTEND_UXTB; TypeSpecifier m_type; ShiftType m_shifttype; u32 m_shift; diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index d71c1efdf2..46a36c8805 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -112,32 +112,29 @@ private: OpType Type; // IMM types - u8 Rotation; // Only for u8 values + u8 Rotation = 0; // Only for u8 values // Register types - u8 IndexOrShift; - ShiftType Shift; + u8 IndexOrShift = 0; + ShiftType Shift = ST_LSL; public: - OpType GetType() const - { + OpType GetType() const { return Type; } - Operand2() {} - Operand2(u32 imm, OpType type = TYPE_IMM) - { - Type = type; - Value = imm; - Rotation = 0; + Operand2() { + Type = TYPE_IMM; + Value = 0; + } + Operand2(u32 imm, OpType type = TYPE_IMM) { + Type = type; + Value = imm; } - Operand2(ARMReg Reg) - { + Operand2(ARMReg Reg) { Type = TYPE_REG; Value = Reg; - Rotation = 0; } - Operand2(u8 imm, u8 rotation) - { + Operand2(u8 imm, u8 rotation) { Type = TYPE_IMM; Value = imm; Rotation = rotation; diff --git a/Common/Buffer.cpp b/Common/Buffer.cpp index 6dc6b74c5a..58a485593c 100644 --- a/Common/Buffer.cpp +++ b/Common/Buffer.cpp @@ -67,7 +67,9 @@ int Buffer::TakeLineCRLF(std::string *dest) { if (after_next_line < 0) { return after_next_line; } else { - Take(after_next_line - 2, dest); + _dbg_assert_(after_next_line >= 2); + if (after_next_line != 2) + Take((size_t)after_next_line - 2, dest); Skip(2); // Skip the CRLF return after_next_line - 2; } diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp index 262bbf4def..ebf78012b6 100644 --- a/Common/CPUDetect.cpp +++ b/Common/CPUDetect.cpp @@ -321,7 +321,10 @@ void CPUInfo::Detect() { #if PPSSPP_PLATFORM(WINDOWS) #if !PPSSPP_PLATFORM(UWP) typedef BOOL (WINAPI *getLogicalProcessorInformationEx_f)(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnedLength); - auto getLogicalProcessorInformationEx = (getLogicalProcessorInformationEx_f)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetLogicalProcessorInformationEx"); + getLogicalProcessorInformationEx_f getLogicalProcessorInformationEx = nullptr; + HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); + if (kernel32) + getLogicalProcessorInformationEx = (getLogicalProcessorInformationEx_f)GetProcAddress(kernel32, "GetLogicalProcessorInformationEx"); #else void *getLogicalProcessorInformationEx = nullptr; #endif diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index 0369c66893..0307cf9df6 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -57,7 +57,10 @@ private: public: CodeBlock() {} - virtual ~CodeBlock() { if (region) FreeCodeSpace(); } + ~CodeBlock() { + if (region) + FreeCodeSpace(); + } // Call this before you generate any code. void AllocCodeSpace(int size) { @@ -80,7 +83,7 @@ public: // If not WX Exclusive, no need to call ProtectMemoryPages because we never change the protection from RWX. PoisonMemory(offset); ResetCodePtr(offset); - if (PlatformIsWXExclusive()) { + if (PlatformIsWXExclusive() && offset != 0) { // Need to re-protect the part we didn't clear. ProtectMemoryPages(region, offset, MEM_PROT_READ | MEM_PROT_EXEC); } @@ -95,15 +98,37 @@ public: // In case the last block made the current page exec/no-write, let's fix that. if (PlatformIsWXExclusive()) { writeStart_ = GetCodePtr(); + if (writeStart_ + sizeEstimate - region > (ptrdiff_t)region_size) + sizeEstimate = region_size - (writeStart_ - region); + writeEstimated_ = sizeEstimate; ProtectMemoryPages(writeStart_, sizeEstimate, MEM_PROT_READ | MEM_PROT_WRITE); } } + // In case you now know your original estimate is wrong. + void ContinueWrite(size_t sizeEstimate = 1) { + _dbg_assert_msg_(writeStart_, "Must have already called BeginWrite()"); + if (PlatformIsWXExclusive()) { + const uint8_t *pos = GetCodePtr(); + if (pos + sizeEstimate - region > (ptrdiff_t)region_size) + sizeEstimate = region_size - (pos - region); + writeEstimated_ = pos - writeStart_ + sizeEstimate; + ProtectMemoryPages(pos, sizeEstimate, MEM_PROT_READ | MEM_PROT_WRITE); + } + } + void EndWrite() { // OK, we're done. Re-protect the memory we touched. if (PlatformIsWXExclusive() && writeStart_ != nullptr) { const uint8_t *end = GetCodePtr(); - ProtectMemoryPages(writeStart_, end - writeStart_, MEM_PROT_READ | MEM_PROT_EXEC); + size_t sz = end - writeStart_; + if (sz > writeEstimated_) + WARN_LOG(JIT, "EndWrite(): Estimated %d bytes, wrote %d", (int)writeEstimated_, (int)sz); + // If we protected and wrote less, we may need to unprotect. + // Especially if we're linking blocks or similar. + if (sz < writeEstimated_) + sz = writeEstimated_; + ProtectMemoryPages(writeStart_, sz, MEM_PROT_READ | MEM_PROT_EXEC); writeStart_ = nullptr; } } @@ -150,5 +175,6 @@ private: // Note: this is a readable pointer. const uint8_t *writeStart_ = nullptr; uint8_t *writableRegion = nullptr; + size_t writeEstimated_ = 0; }; diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index aa0f9bb1e7..d51b49d585 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -136,7 +136,7 @@ _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) Common/DbgNew.h MultiThreadedDebug - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib StreamingSIMDExtensions2 Precise true @@ -162,7 +162,7 @@ Common/DbgNew.h MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib NotSet Precise false @@ -189,7 +189,7 @@ Common/DbgNew.h MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib NotSet Precise false @@ -217,7 +217,7 @@ MultiThreadedDebug _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib NotSet Precise false @@ -250,7 +250,7 @@ false StreamingSIMDExtensions2 Precise - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib Speed true false @@ -280,7 +280,7 @@ USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib false NotSet Precise @@ -315,7 +315,7 @@ USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib false NotSet Precise @@ -350,7 +350,7 @@ USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib + ../ext/openxr;../ext/glew;../ext/snappy;../ext/glslang;../ext/libpng17;../ext;../ext/zlib;..;../ext/zstd/lib false NotSet Precise @@ -432,6 +432,7 @@ + @@ -449,6 +450,7 @@ + @@ -477,6 +479,7 @@ + @@ -549,6 +552,7 @@ + @@ -557,6 +561,13 @@ + + + + + + + @@ -871,6 +882,7 @@ + @@ -898,6 +910,7 @@ + @@ -981,6 +994,7 @@ + @@ -989,6 +1003,13 @@ + + + + + + + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 0cb9e79423..18cbbd9985 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -425,6 +425,39 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + UI + + + Render + + + GPU + + + GPU\Vulkan + @@ -803,6 +836,36 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + UI + + + Render + + + GPU\Vulkan + @@ -907,6 +970,9 @@ {7b17065c-729c-47c3-a02d-66dc383529dd} + + {9d1c29fd-8ac7-4475-8ea6-c8c759b695fe} + diff --git a/Common/ConsoleListener.h b/Common/ConsoleListener.h index 976e7531cd..99c6730750 100644 --- a/Common/ConsoleListener.h +++ b/Common/ConsoleListener.h @@ -41,7 +41,7 @@ public: #if defined(USING_WIN_UI) COORD GetCoordinates(int BytesRead, int BufferWidth); #endif - void Log(const LogMessage &message); + void Log(const LogMessage &message) override; void ClearScreen(bool Cursor = true); void Show(bool bShow); @@ -66,8 +66,8 @@ private: static std::atomic logPendingReadPos; static std::atomic logPendingWritePos; - int openWidth_; - int openHeight_; + int openWidth_ = 0; + int openHeight_ = 0; std::wstring title_; #endif bool bHidden; diff --git a/Common/Data/Color/RGBAUtil.h b/Common/Data/Color/RGBAUtil.h index 9e8128bae1..3ea03f328a 100644 --- a/Common/Data/Color/RGBAUtil.h +++ b/Common/Data/Color/RGBAUtil.h @@ -16,3 +16,9 @@ typedef unsigned int Color; inline Color darkenColor(Color color) { return (color & 0xFF000000) | ((color >> 1) & 0x7F7F7F); } + +inline Color lightenColor(Color color) { + color = ~color; + color = (color & 0xFF000000) | ((color >> 1) & 0x7F7F7F); + return ~color; +} diff --git a/Common/Data/Convert/ColorConv.cpp b/Common/Data/Convert/ColorConv.cpp index 55686f5c00..01c434e6e5 100644 --- a/Common/Data/Convert/ColorConv.cpp +++ b/Common/Data/Convert/ColorConv.cpp @@ -34,88 +34,6 @@ #endif #endif -// convert 4444 image to 8888, parallelizable -void convert4444_gl(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = ((val >> 12) & 0xF) * 17; - u32 g = ((val >> 8) & 0xF) * 17; - u32 b = ((val >> 4) & 0xF) * 17; - u32 a = ((val >> 0) & 0xF) * 17; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 565 image to 8888, parallelizable -void convert565_gl(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val >> 11) & 0x1F); - u32 g = Convert6To8((val >> 5) & 0x3F); - u32 b = Convert5To8((val)& 0x1F); - out[y*width + x] = (0xFF << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 5551 image to 8888, parallelizable -void convert5551_gl(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val >> 11) & 0x1F); - u32 g = Convert5To8((val >> 6) & 0x1F); - u32 b = Convert5To8((val >> 1) & 0x1F); - u32 a = (val & 0x1) * 255; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 4444 image to 8888, parallelizable -void convert4444_dx9(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = ((val >> 0) & 0xF) * 17; - u32 g = ((val >> 4) & 0xF) * 17; - u32 b = ((val >> 8) & 0xF) * 17; - u32 a = ((val >> 12) & 0xF) * 17; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 565 image to 8888, parallelizable -void convert565_dx9(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val)& 0x1F); - u32 g = Convert6To8((val >> 5) & 0x3F); - u32 b = Convert5To8((val >> 11) & 0x1F); - out[y*width + x] = (0xFF << 24) | (b << 16) | (g << 8) | r; - } - } -} - -// convert 5551 image to 8888, parallelizable -void convert5551_dx9(u16* data, u32* out, int width, int l, int u) { - for (int y = l; y < u; ++y) { - for (int x = 0; x < width; ++x) { - u32 val = data[y*width + x]; - u32 r = Convert5To8((val >> 0) & 0x1F); - u32 g = Convert5To8((val >> 5) & 0x1F); - u32 b = Convert5To8((val >> 10) & 0x1F); - u32 a = ((val >> 15) & 0x1) * 255; - out[y*width + x] = (a << 24) | (b << 16) | (g << 8) | r; - } - } -} - void ConvertBGRA8888ToRGBA8888(u32 *dst, const u32 *src, u32 numPixels) { #ifdef _M_SSE const __m128i maskGA = _mm_set1_epi32(0xFF00FF00); diff --git a/Common/Data/Convert/ColorConv.h b/Common/Data/Convert/ColorConv.h index 077533171b..53a286d127 100644 --- a/Common/Data/Convert/ColorConv.h +++ b/Common/Data/Convert/ColorConv.h @@ -101,6 +101,14 @@ inline u16 RGBA8888ToRGBA5551(u32 value) { return (u16)(r | g | b | a); } +// Used in fast sprite path. +inline u16 RGBA8888ToRGBA555X(u32 value) { + u32 r = (value >> 3) & 0x1F; + u32 g = (value >> 6) & (0x1F << 5); + u32 b = (value >> 9) & (0x1F << 10); + return (u16)(r | g | b); +} + inline u16 RGBA8888ToRGBA4444(u32 value) { const u32 c = value >> 4; const u16 r = (c >> 0) & 0x000F; @@ -110,14 +118,13 @@ inline u16 RGBA8888ToRGBA4444(u32 value) { return r | g | b | a; } -// convert image to 8888, parallelizable -// TODO: Implement these in terms of the conversion functions below. -void convert4444_gl(u16* data, u32* out, int width, int l, int u); -void convert565_gl(u16* data, u32* out, int width, int l, int u); -void convert5551_gl(u16* data, u32* out, int width, int l, int u); -void convert4444_dx9(u16* data, u32* out, int width, int l, int u); -void convert565_dx9(u16* data, u32* out, int width, int l, int u); -void convert5551_dx9(u16* data, u32* out, int width, int l, int u); +inline u16 RGBA8888ToRGBA444X(u32 value) { + const u32 c = value >> 4; + const u16 r = (c >> 0) & 0x000F; + const u16 g = (c >> 4) & 0x00F0; + const u16 b = (c >> 8) & 0x0F00; + return r | g | b; +} // "Complete" set of color conversion functions between the usual formats. diff --git a/Common/Data/Convert/SmallDataConvert.cpp b/Common/Data/Convert/SmallDataConvert.cpp index 4f0d65ea11..ee2673aba1 100644 --- a/Common/Data/Convert/SmallDataConvert.cpp +++ b/Common/Data/Convert/SmallDataConvert.cpp @@ -1,3 +1,4 @@ #include "Common/Data/Convert/SmallDataConvert.h" alignas(16) const float one_over_255_x4[4] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, }; +alignas(16) const float exactly_255_x4[4] = { 255.0f, 255.0f, 255.0f, 255.0f, }; diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 95558a17df..0449d3df16 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -18,12 +18,12 @@ #endif extern const float one_over_255_x4[4]; +extern const float exactly_255_x4[4]; // Utilities useful for filling in std140-layout uniform buffers, and similar. -// NEON intrinsics: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491f/BABDCGGF.html +// NEON intrinsics: https://developer.arm.com/documentation/den0018/a/NEON-Intrinsics?lang=en // LSBs in f[0], etc. -// Could be SSE optimized. inline void Uint8x4ToFloat4(float f[4], uint32_t u) { #ifdef _M_SSE __m128i zero = _mm_setzero_si128(); @@ -47,6 +47,19 @@ inline void Uint8x4ToFloat4(float f[4], uint32_t u) { // Could be SSE optimized. inline uint32_t Float4ToUint8x4(const float f[4]) { +#ifdef _M_SSE + __m128i zero = _mm_setzero_si128(); + __m128 value = _mm_mul_ps(_mm_loadu_ps(f), _mm_load_ps(exactly_255_x4)); + __m128i ivalue = _mm_packus_epi16(_mm_packs_epi32(_mm_cvtps_epi32(value), zero), zero); + return _mm_cvtsi128_si32(ivalue); +#elif PPSSPP_ARCH(ARM_NEON) + const float32x4_t value = vmulq_f32(vld1q_f32(f), vdupq_n_f32(255.0f)); + uint32x4_t ivalue32 = vcvtq_u32_f32(value); + uint16x4_t ivalue16 = vqmovn_u32(ivalue32); + uint8x8_t ivalue8 = vqmovn_u16(vcombine_u16(ivalue16, ivalue16)); // Is there no way to avoid the combine here? + uint32x2_t outValue32 = vreinterpret_u32_u8(ivalue8); + return vget_lane_u32(outValue32, 0); +#else int i4[4]; for (int i = 0; i < 4; i++) { if (f[i] > 1.0f) { @@ -58,6 +71,30 @@ inline uint32_t Float4ToUint8x4(const float f[4]) { } } return i4[0] | (i4[1] << 8) | (i4[2] << 16) | (i4[3] << 24); +#endif +} + +inline uint32_t Float4ToUint8x4_NoClamp(const float f[4]) { +#ifdef _M_SSE + // Does actually clamp, no way to avoid it with the pack ops! + __m128i zero = _mm_setzero_si128(); + __m128 value = _mm_mul_ps(_mm_loadu_ps(f), _mm_load_ps(exactly_255_x4)); + __m128i ivalue = _mm_packus_epi16(_mm_packs_epi32(_mm_cvtps_epi32(value), zero), zero); + return _mm_cvtsi128_si32(ivalue); +#elif PPSSPP_ARCH(ARM_NEON) + const float32x4_t value = vmulq_f32(vld1q_f32(f), vdupq_n_f32(255.0f)); + uint32x4_t ivalue32 = vcvtq_u32_f32(value); + uint16x4_t ivalue16 = vqmovn_u32(ivalue32); + uint8x8_t ivalue8 = vqmovn_u16(vcombine_u16(ivalue16, ivalue16)); // Is there no way to avoid the combine here? + uint32x2_t outValue32 = vreinterpret_u32_u8(ivalue8); + return vget_lane_u32(outValue32, 0); +#else + u32 i4[4]; + for (int i = 0; i < 4; i++) { + i4[i] = (int)(f[i] * 255.0f); + } + return i4[0] | (i4[1] << 8) | (i4[2] << 16) | (i4[3] << 24); +#endif } inline void Uint8x3ToFloat4_AlphaUint8(float f[4], uint32_t u, uint8_t alpha) { diff --git a/Common/Data/Encoding/Utf8.cpp b/Common/Data/Encoding/Utf8.cpp index d3ddbdbc21..760fe6b07d 100644 --- a/Common/Data/Encoding/Utf8.cpp +++ b/Common/Data/Encoding/Utf8.cpp @@ -112,7 +112,7 @@ int u8_toucs(uint32_t *dest, int sz, const char *src, int srcsz) the NUL as well. the destination string will never be bigger than the source string. */ -int u8_toutf8(char *dest, int sz, uint32_t *src, int srcsz) +int u8_toutf8(char *dest, int sz, const uint32_t *src, int srcsz) { uint32_t ch; int i = 0; @@ -219,19 +219,14 @@ int u8_strlen(const char *s) } /* reads the next utf-8 sequence out of a string, updating an index */ -uint32_t u8_nextchar(const char *s, int *i) -{ - uint32_t ch = 0; - int sz = 0; - - do { - ch <<= 6; - ch += (unsigned char)s[(*i)++]; - sz++; - } while (s[*i] && !isutf(s[*i])); - ch -= offsetsFromUTF8[sz-1]; - - return ch; +uint32_t u8_nextchar(const char *s, int *i) { + uint32_t ch = 0; + int sz = 0; + do { + ch = (ch << 6) + (unsigned char)s[(*i)++]; + sz++; + } while (s[*i] && ((s[*i]) & 0xC0) == 0x80); + return ch - offsetsFromUTF8[sz - 1]; } uint32_t u8_nextchar_unsafe(const char *s, int *i) { diff --git a/Common/Data/Format/IniFile.cpp b/Common/Data/Format/IniFile.cpp index cd2a658e5c..72aeee6f89 100644 --- a/Common/Data/Format/IniFile.cpp +++ b/Common/Data/Format/IniFile.cpp @@ -174,6 +174,19 @@ std::string* Section::GetLine(const char* key, std::string* valueOut, std::strin return 0; } +const std::string* Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) const +{ + for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) + { + const std::string& line = *iter; + std::string lineKey; + ParseLine(line, &lineKey, valueOut, commentOut); + if (!strcasecmp(lineKey.c_str(), key)) + return &line; + } + return 0; +} + void Section::Set(const char* key, uint32_t newValue) { Set(key, StringFromFormat("0x%08x", newValue).c_str()); } @@ -218,7 +231,7 @@ void Section::Set(const char* key, const std::string& newValue, const std::strin Delete(key); } -bool Section::Get(const char* key, std::string* value, const char* defaultValue) +bool Section::Get(const char* key, std::string* value, const char* defaultValue) const { const std::string* line = GetLine(key, value, 0); if (!line) @@ -275,7 +288,7 @@ void Section::AddComment(const std::string &comment) { lines.emplace_back("# " + comment); } -bool Section::Get(const char* key, std::vector& values) +bool Section::Get(const char* key, std::vector& values) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -303,7 +316,7 @@ bool Section::Get(const char* key, std::vector& values) return true; } -bool Section::Get(const char* key, int* value, int defaultValue) +bool Section::Get(const char* key, int* value, int defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -313,7 +326,7 @@ bool Section::Get(const char* key, int* value, int defaultValue) return false; } -bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) +bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -323,7 +336,7 @@ bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) return false; } -bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) +bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -333,7 +346,7 @@ bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) return false; } -bool Section::Get(const char* key, bool* value, bool defaultValue) +bool Section::Get(const char* key, bool* value, bool defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -343,7 +356,7 @@ bool Section::Get(const char* key, bool* value, bool defaultValue) return false; } -bool Section::Get(const char* key, float* value, float defaultValue) +bool Section::Get(const char* key, float* value, float defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); @@ -353,7 +366,7 @@ bool Section::Get(const char* key, float* value, float defaultValue) return false; } -bool Section::Get(const char* key, double* value, double defaultValue) +bool Section::Get(const char* key, double* value, double defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); diff --git a/Common/Data/Format/IniFile.h b/Common/Data/Format/IniFile.h index 87bd1d1830..707f0ab3eb 100644 --- a/Common/Data/Format/IniFile.h +++ b/Common/Data/Format/IniFile.h @@ -25,14 +25,16 @@ public: std::map ToMap() const; - std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); + std::string *GetLine(const char* key, std::string* valueOut, std::string* commentOut); + const std::string *GetLine(const char* key, std::string* valueOut, std::string* commentOut) const; + void Set(const char* key, const char* newValue); void Set(const char* key, const std::string& newValue, const std::string& defaultValue); void Set(const std::string &key, const std::string &value) { Set(key.c_str(), value.c_str()); } - bool Get(const char* key, std::string* value, const char* defaultValue); + bool Get(const char* key, std::string* value, const char* defaultValue) const; void Set(const char* key, uint32_t newValue); void Set(const char* key, uint64_t newValue); @@ -57,13 +59,13 @@ public: void AddComment(const std::string &comment); - bool Get(const char* key, int* value, int defaultValue = 0); - bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0); - bool Get(const char* key, uint64_t* value, uint64_t defaultValue = 0); - bool Get(const char* key, bool* value, bool defaultValue = false); - bool Get(const char* key, float* value, float defaultValue = false); - bool Get(const char* key, double* value, double defaultValue = false); - bool Get(const char* key, std::vector& values); + bool Get(const char* key, int* value, int defaultValue = 0) const; + bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0) const; + bool Get(const char* key, uint64_t* value, uint64_t defaultValue = 0) const; + bool Get(const char* key, bool* value, bool defaultValue = false) const; + bool Get(const char* key, float* value, float defaultValue = false) const; + bool Get(const char* key, double* value, double defaultValue = false) const; + bool Get(const char* key, std::vector& values) const; bool operator < (const Section& other) const { return name_ < other.name_; diff --git a/Common/Data/Format/JSONReader.h b/Common/Data/Format/JSONReader.h index 4156650301..792d6a669a 100644 --- a/Common/Data/Format/JSONReader.h +++ b/Common/Data/Format/JSONReader.h @@ -47,9 +47,11 @@ public: JsonReader(const std::string &filename); JsonReader(const void *data, size_t size) { buffer_ = (char *)malloc(size + 1); - memcpy(buffer_, data, size); - buffer_[size] = 0; - parse(); + if (buffer_) { + memcpy(buffer_, data, size); + buffer_[size] = 0; + parse(); + } } JsonReader(const JsonNode *node) { ok_ = true; diff --git a/Common/Data/Text/WrapText.h b/Common/Data/Text/WrapText.h index bcdd19a6fd..d51f860362 100644 --- a/Common/Data/Text/WrapText.h +++ b/Common/Data/Text/WrapText.h @@ -7,6 +7,7 @@ public: WordWrapper(const char *str, float maxW, int flags) : str_(str), maxW_(maxW), flags_(flags) { } + virtual ~WordWrapper() {} std::string Wrapped(); diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 5594f9a5ce..deb78eb139 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -127,7 +127,7 @@ static void ExceptionThread(mach_port_t port) { #pragma pack() memset(&msg_in, 0xee, sizeof(msg_in)); memset(&msg_out, 0xee, sizeof(msg_out)); - mach_msg_header_t* send_msg = nullptr; + mach_msg_header_t* send_msg = &msg_out.Head; mach_msg_size_t send_size = 0; mach_msg_option_t option = MACH_RCV_MSG; while (true) { diff --git a/Common/File/DirListing.cpp b/Common/File/DirListing.cpp index d17a4f2241..b793e85057 100644 --- a/Common/File/DirListing.cpp +++ b/Common/File/DirListing.cpp @@ -317,7 +317,7 @@ std::vector GetWindowsDrives() { if (logicaldrives & (1 << i)) { - CHAR driveName[] = { TEXT('A') + i, TEXT(':'), TEXT('\\'), TEXT('\0') }; + CHAR driveName[] = { (CHAR)(TEXT('A') + i), TEXT(':'), TEXT('\\'), TEXT('\0') }; std::string str(driveName); drives.push_back(driveName); } diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 8bab82ae6e..e8088e90bc 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -141,7 +141,7 @@ FILE *OpenCFile(const Path &path, const char *mode) { return nullptr; } FILE *f = fdopen(descriptor, "wb"); - if (!strcmp(mode, "at") || !strcmp(mode, "a")) { + if (f && (!strcmp(mode, "at") || !strcmp(mode, "a"))) { // Append mode. fseek(f, 0, SEEK_END); } @@ -250,7 +250,8 @@ static bool ResolvePathVista(const std::wstring &path, wchar_t *buf, DWORD bufSi #else if (!getFinalPathNameByHandleW) { HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - getFinalPathNameByHandleW = (getFinalPathNameByHandleW_f)GetProcAddress(kernel32, "GetFinalPathNameByHandleW"); + if (kernel32) + getFinalPathNameByHandleW = (getFinalPathNameByHandleW_f)GetProcAddress(kernel32, "GetFinalPathNameByHandleW"); } #endif diff --git a/Common/File/Path.h b/Common/File/Path.h index ab49fb10cf..aded7b5bde 100644 --- a/Common/File/Path.h +++ b/Common/File/Path.h @@ -118,6 +118,9 @@ public: bool operator <(const Path &other) const { return path_ < other.path_; } + bool operator >(const Path &other) const { + return path_ > other.path_; + } private: // The internal representation is currently always the plain string. diff --git a/Common/File/VFS/AssetReader.h b/Common/File/VFS/AssetReader.h index df0c4f2821..36ccd60161 100644 --- a/Common/File/VFS/AssetReader.h +++ b/Common/File/VFS/AssetReader.h @@ -47,10 +47,10 @@ class DirectoryAssetReader : public AssetReader { public: explicit DirectoryAssetReader(const Path &path); // use delete[] - virtual uint8_t *ReadAsset(const char *path, size_t *size); - virtual bool GetFileListing(const char *path, std::vector *listing, const char *filter); - virtual bool GetFileInfo(const char *path, File::FileInfo *info); - virtual std::string toString() const { + uint8_t *ReadAsset(const char *path, size_t *size) override; + bool GetFileListing(const char *path, std::vector *listing, const char *filter) override; + bool GetFileInfo(const char *path, File::FileInfo *info) override; + std::string toString() const override { return path_.ToString(); } diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 0b10980c0f..aa52c919dd 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -95,16 +95,13 @@ public: // These functions should be self explanatory. void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return curRenderTarget_; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; - void InvalidateCachedState() override; + void Invalidate(InvalidationFlags flags) override; - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int index, void *nativeTexture) override; void BindSamplerStates(int start, int count, SamplerState **states) override; void BindVertexBuffers(int start, int count, Buffer **buffers, const int *offsets) override; @@ -166,21 +163,20 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - int GetCurrentStepId() const override { - return stepId_; + void SetInvalidationCallback(InvalidationCallback callback) override { + invalidationCallback_ = callback; } private: void ApplyCurrentState(); - ID3D11DepthStencilState *GetCachedDepthStencilState(D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask); + ID3D11DepthStencilState *GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask); HWND hWnd_; ID3D11Device *device_; ID3D11DeviceContext *context_; ID3D11Device1 *device1_; ID3D11DeviceContext1 *context1_; - int stepId_ = -1; ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED ID3D11RenderTargetView *bbRenderTargetView_ = nullptr; @@ -219,6 +215,8 @@ private: ID3D11Buffer *nextIndexBuffer_ = nullptr; int nextIndexBufferOffset_ = 0; + InvalidationCallback invalidationCallback_; + // Dynamic state float blendFactor_[4]{}; bool blendFactorDirty_ = false; @@ -264,13 +262,16 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferStencilBlitSupported = false; caps_.framebufferDepthCopySupported = true; caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw. + caps_.preferredDepthBufferFormat = DataFormat::D24_S8; caps_.textureDepthSupported = true; caps_.texture3DSupported = true; caps_.fragmentShaderInt32Supported = true; caps_.anisoSupported = true; caps_.textureNPOTFullySupported = true; caps_.fragmentShaderDepthWriteSupported = true; + caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; + caps_.multiSampleLevelsMask = 1; // More could be supported with some work. D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options)); @@ -309,6 +310,14 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de dxgiDevice->Release(); } + caps_.isTilingGPU = false; + + // Hide D3D9 when we know it likely won't work well. + caps_.supportsD3D9 = true; + if (!strcmp(adapterDesc_.c_str(), "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } + // Temp texture for read-back of small images. Custom textures are created on demand for larger ones. // TODO: Should really benchmark if this extra complexity has any benefit. D3D11_TEXTURE2D_DESC packDesc{}; @@ -401,7 +410,6 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1 // Make sure that we don't eliminate the next time the render target is set. curRenderTargetView_ = nullptr; curDepthStencilView_ = nullptr; - stepId_ = 0; break; } } @@ -548,7 +556,7 @@ public: float blendFactor[4]; }; -ID3D11DepthStencilState *D3D11DrawContext::GetCachedDepthStencilState(D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask) { +ID3D11DepthStencilState *D3D11DrawContext::GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask) { D3D11DepthStencilKey key; key.desc = state->desc; key.writeMask = stencilWriteMask; @@ -1081,17 +1089,19 @@ void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { context_->Unmap(curPipeline_->dynamicUniforms, 0); } -void D3D11DrawContext::InvalidateCachedState() { - // This is a signal to forget all our state caching. - curBlend_ = nullptr; - curDepthStencil_ = nullptr; - curRaster_ = nullptr; - curPS_ = nullptr; - curVS_ = nullptr; - curGS_ = nullptr; - curInputLayout_ = nullptr; - curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; - curPipeline_ = nullptr; +void D3D11DrawContext::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + // This is a signal to forget all our state caching. + curBlend_ = nullptr; + curDepthStencil_ = nullptr; + curRaster_ = nullptr; + curPS_ = nullptr; + curVS_ = nullptr; + curGS_ = nullptr; + curInputLayout_ = nullptr; + curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + curPipeline_ = nullptr; + } } void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { @@ -1306,35 +1316,38 @@ public: Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { HRESULT hr; D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height); - if (desc.numColorAttachments) { - fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - D3D11_TEXTURE2D_DESC descColor{}; - descColor.Width = desc.width; - descColor.Height = desc.height; - descColor.MipLevels = 1; - descColor.ArraySize = 1; - descColor.Format = fb->colorFormat; - descColor.SampleDesc.Count = 1; - descColor.SampleDesc.Quality = 0; - descColor.Usage = D3D11_USAGE_DEFAULT; - descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - descColor.CPUAccessFlags = 0; - descColor.MiscFlags = 0; - hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex); - if (FAILED(hr)) { - delete fb; - return nullptr; - } - hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView); - if (FAILED(hr)) { - delete fb; - return nullptr; - } - hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView); - if (FAILED(hr)) { - delete fb; - return nullptr; - } + + // We don't (yet?) support multiview for D3D11. Not sure if there's a way to do it. + // Texture arrays are supported but we don't have any other use cases yet. + _dbg_assert_(desc.numLayers == 1); + + fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + D3D11_TEXTURE2D_DESC descColor{}; + descColor.Width = desc.width; + descColor.Height = desc.height; + descColor.MipLevels = 1; + descColor.ArraySize = 1; + descColor.Format = fb->colorFormat; + descColor.SampleDesc.Count = 1; + descColor.SampleDesc.Quality = 0; + descColor.Usage = D3D11_USAGE_DEFAULT; + descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + descColor.CPUAccessFlags = 0; + descColor.MiscFlags = 0; + hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView); + if (FAILED(hr)) { + delete fb; + return nullptr; } if (desc.z_stencil) { @@ -1381,7 +1394,7 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { return fb; } -void D3D11DrawContext::BindTextures(int start, int count, Texture **textures) { +void D3D11DrawContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { // Collect the resource views from the textures. ID3D11ShaderResourceView *views[MAX_BOUND_TEXTURES]; _assert_(start + count <= ARRAY_SIZE(views)); @@ -1469,6 +1482,7 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x dstTex = dst->depthStencilTex; break; } + _assert_(srcTex && dstTex); // TODO: Check for level too! if (width == src->Width() && width == dst->Width() && height == src->Height() && height == dst->Height() && x == 0 && y == 0 && z == 0 && dstX == 0 && dstY == 0 && dstZ == 0) { @@ -1499,13 +1513,11 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) }; context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox); } - stepId_++; } bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) { // Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead. Crash(); - stepId_++; return false; } @@ -1529,7 +1541,7 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel bool useGlobalPacktex = (bx + bw <= 512 && by + bh <= 512) && channelBits == FB_COLOR_BIT; - ID3D11Texture2D *packTex; + ID3D11Texture2D *packTex = nullptr; if (!useGlobalPacktex) { D3D11_TEXTURE2D_DESC packDesc{}; packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; @@ -1568,6 +1580,9 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel packTex = packTexture_; } + if (!packTex) + return false; + D3D11_BOX srcBox{ (UINT)bx, (UINT)by, 0, (UINT)(bx + bw), (UINT)(by + bh), 1 }; DataFormat srcFormat = DataFormat::UNDEFINED; switch (channelBits) { @@ -1651,7 +1666,6 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel if (!useGlobalPacktex) { packTex->Release(); } - stepId_++; return true; } @@ -1698,11 +1712,14 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren context_->ClearDepthStencilView(curDepthStencilView_, mask, rp.clearDepth, rp.clearStencil); } - stepId_++; + if (invalidationCallback_) { + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); + } } -void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { - _assert_(binding < MAX_BOUND_TEXTURES); +void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { + _dbg_assert_(binding < MAX_BOUND_TEXTURES); + _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; switch (channelBit) { case FBChannel::FB_COLOR_BIT: diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 20bcc14e5d..a4d668e369 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -291,7 +291,7 @@ public: D3D9Texture(LPDIRECT3DDEVICE9 device, LPDIRECT3DDEVICE9EX deviceEx, const TextureDesc &desc); ~D3D9Texture(); void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler); - LPDIRECT3DBASETEXTURE9 Texture() const { + LPDIRECT3DBASETEXTURE9 TexturePtr() const { // TODO: Cleanup if (tex_) { return tex_; @@ -532,16 +532,13 @@ public: // These functions should be self explanatory. void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return curRenderTarget_; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; - + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; + uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int index, void *nativeTexture) override; void BindSamplerStates(int start, int count, SamplerState **states) override { @@ -593,7 +590,7 @@ public: case NativeObject::DEVICE_EX: return (uint64_t)(uintptr_t)deviceEx_; case NativeObject::TEXTURE_VIEW: - return (uint64_t)(((D3D9Texture *)srcObject)->Texture()); + return (uint64_t)(((D3D9Texture *)srcObject)->TexturePtr()); default: return 0; } @@ -613,18 +610,17 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - int GetCurrentStepId() const override { - return stepId_; - } + void Invalidate(InvalidationFlags flags) override; - void InvalidateCachedState() override; + void SetInvalidationCallback(InvalidationCallback callback) override { + invalidationCallback_ = callback; + } private: LPDIRECT3D9 d3d_; LPDIRECT3D9EX d3dEx_; LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9EX deviceEx_; - int stepId_ = -1; int adapterId_ = -1; D3DADAPTER_IDENTIFIER9 identifier_{}; D3DCAPS9 d3dCaps_; @@ -650,10 +646,14 @@ private: // Dynamic state uint8_t stencilRef_ = 0; + + InvalidationCallback invalidationCallback_; }; -void D3D9Context::InvalidateCachedState() { - curPipeline_ = nullptr; +void D3D9Context::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + curPipeline_ = nullptr; + } } // TODO: Move this detection elsewhere when it's needed elsewhere, not before. It's ugly. @@ -749,7 +749,6 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID } caps_.deviceID = identifier_.DeviceId; - caps_.multiViewport = false; caps_.depthRangeMinusOneToOne = false; caps_.preferredDepthBufferFormat = DataFormat::D24_S8; caps_.dualSourceBlend = false; @@ -762,7 +761,10 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; caps_.fragmentShaderDepthWriteSupported = true; + caps_.fragmentShaderStencilWriteSupported = false; caps_.blendMinMaxSupported = true; + caps_.isTilingGPU = false; + caps_.multiSampleLevelsMask = 1; // More could be supported with some work. if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) { caps_.anisoSupported = true; @@ -771,6 +773,11 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.textureNPOTFullySupported = true; } + caps_.supportsD3D9 = true; + if (!strcmp(identifier_.Description, "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } + // VS range culling (killing triangles in the vertex shader using NaN) causes problems on Intel. // Also causes problems on old NVIDIA. switch (caps_.vendor) { @@ -915,7 +922,7 @@ Texture *D3D9Context::CreateTexture(const TextureDesc &desc) { return tex; } -void D3D9Context::BindTextures(int start, int count, Texture **textures) { +void D3D9Context::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_BOUND_TEXTURES); for (int i = start; i < start + count; i++) { D3D9Texture *tex = static_cast(textures[i - start]); @@ -1005,7 +1012,7 @@ public: device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL); } } - virtual ~D3D9Buffer() override { + ~D3D9Buffer() { if (ibuffer_) { ibuffer_->Release(); } @@ -1070,16 +1077,16 @@ void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offse return; } if (buf->vbuffer_) { - void *ptr; + void *ptr = nullptr; HRESULT res = buf->vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0); - if (!FAILED(res)) { + if (!FAILED(res) && ptr) { memcpy(ptr, data, size); buf->vbuffer_->Unlock(); } } else if (buf->ibuffer_) { - void *ptr; + void *ptr = nullptr; HRESULT res = buf->ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0); - if (!FAILED(res)) { + if (!FAILED(res) && ptr) { memcpy(ptr, data, size); buf->ibuffer_->Unlock(); } @@ -1244,15 +1251,18 @@ public: }; Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { + // Don't think D3D9 does array layers. + _dbg_assert_(desc.numLayers == 1); + static uint32_t id = 0; D3D9Framebuffer *fbo = new D3D9Framebuffer(desc.width, desc.height); fbo->depthstenciltex = nullptr; - HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, NULL); + HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, nullptr); if (FAILED(rtResult)) { ERROR_LOG(G3D, "Failed to create render target"); - delete fbo; + fbo->Release(); return NULL; } fbo->tex->GetSurfaceLevel(0, &fbo->surf); @@ -1281,9 +1291,15 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { } D3D9Framebuffer::~D3D9Framebuffer() { - tex->Release(); - surf->Release(); - depthstencil->Release(); + if (tex) { + tex->Release(); + } + if (surf) { + surf->Release(); + } + if (depthstencil) { + depthstencil->Release(); + } if (depthstenciltex) { depthstenciltex->Release(); } @@ -1320,7 +1336,10 @@ void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPa dxstate.scissorRect.restore(); dxstate.scissorTest.restore(); dxstate.viewport.restore(); - stepId_++; + + if (invalidationCallback_) { + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); + } } uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) { @@ -1348,8 +1367,9 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit } } -void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int color) { - _assert_(binding < MAX_BOUND_TEXTURES); +void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { + _dbg_assert_(binding < MAX_BOUND_TEXTURES); + _dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; switch (channelBit) { case FB_DEPTH_BIT: @@ -1398,7 +1418,6 @@ bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int } else { return false; } - stepId_++; return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, (filter == FB_BLIT_LINEAR && channelBits == FB_COLOR_BIT) ? D3DTEXF_LINEAR : D3DTEXF_POINT)); } @@ -1430,6 +1449,7 @@ bool D3D9Context::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, LPDIRECT3DSURFACE9 offscreen = nullptr; HRESULT hr = E_UNEXPECTED; + _assert_(fb != nullptr); if (channelBits == FB_COLOR_BIT) { fb->tex->GetLevelDesc(0, &desc); @@ -1519,7 +1539,6 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi device_->GetDepthStencilSurface(&deviceDSsurf); break; case Event::PRESENTED: - stepId_ = 0; break; } } diff --git a/Common/GPU/DataFormat.h b/Common/GPU/DataFormat.h index 0c8a93e627..32463d3a16 100644 --- a/Common/GPU/DataFormat.h +++ b/Common/GPU/DataFormat.h @@ -65,6 +65,7 @@ enum class DataFormat : uint8_t { S8, D16, + D16_S8, D24_S8, D32F, D32F_S8, @@ -76,6 +77,9 @@ inline bool DataFormatIsColor(DataFormat fmt) { return !DataFormatIsDepthStencil(fmt); } +// Limited format support for now. +const char *DataFormatToString(DataFormat fmt); + void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format); diff --git a/Common/GPU/MiscTypes.h b/Common/GPU/MiscTypes.h new file mode 100644 index 0000000000..0db111a73d --- /dev/null +++ b/Common/GPU/MiscTypes.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Common/Common.h" + +enum class InvalidationFlags { + CACHED_RENDER_STATE = 1, +}; +ENUM_CLASS_BITOPS(InvalidationFlags); + +enum class InvalidationCallbackFlags { + RENDER_PASS_STATE = 1, + COMMAND_BUFFER_STATE = 2, +}; +ENUM_CLASS_BITOPS(InvalidationCallbackFlags); + +typedef std::function InvalidationCallback; diff --git a/Common/GPU/OpenGL/GLFeatures.cpp b/Common/GPU/OpenGL/GLFeatures.cpp index ecec49c82e..06ef1ead3b 100644 --- a/Common/GPU/OpenGL/GLFeatures.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -371,6 +371,7 @@ void CheckGLExtensions() { gl_extensions.ARB_uniform_buffer_object = g_set_gl_extensions.count("GL_ARB_uniform_buffer_object") != 0; gl_extensions.ARB_explicit_attrib_location = g_set_gl_extensions.count("GL_ARB_explicit_attrib_location") != 0; gl_extensions.ARB_texture_non_power_of_two = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0; + gl_extensions.ARB_shader_stencil_export = g_set_gl_extensions.count("GL_ARB_shader_stencil_export") != 0; if (gl_extensions.IsGLES) { gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0; gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_OES_texture_npot") != 0; diff --git a/Common/GPU/OpenGL/GLFeatures.h b/Common/GPU/OpenGL/GLFeatures.h index 0e07fd266f..a2d20b178f 100644 --- a/Common/GPU/OpenGL/GLFeatures.h +++ b/Common/GPU/OpenGL/GLFeatures.h @@ -72,6 +72,7 @@ struct GLExtensions { bool ARB_uniform_buffer_object; bool ARB_texture_non_power_of_two; bool ARB_stencil_texturing; + bool ARB_shader_stencil_export; // EXT bool EXT_swap_control_tear; diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index c63f42301a..bf27a4fcfa 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -280,7 +280,7 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski _dbg_assert_(query.name); int location = -1; - if (IsVRBuild() && IsMultiviewSupported()) { + if (IsVREnabled() && IsMultiviewSupported()) { int index = GetStereoBufferIndex(query.name); if (index >= 0) { std::string layout = GetStereoBufferLayout(query.name); @@ -648,7 +648,7 @@ retry_depth: currentReadHandle_ = fbo->handle; } -void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps) { +void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps, bool useVR) { if (skipGLCalls) { if (keepSteps) { return; @@ -707,7 +707,7 @@ void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCal switch (step.stepType) { case GLRStepType::RENDER: renderCount++; - if (IsVRBuild()) { + if (IsVREnabled()) { GLRStep vrStep = step; PreprocessStepVR(&vrStep); PerformRenderPass(vrStep, renderCount == 1, renderCount == totalRenderCount); @@ -1603,6 +1603,9 @@ void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) { fbo_bind_fb_target(false, curFB_->handle); } else { fbo_unbind(); + if (IsVREnabled()) { + BindVRFramebuffer(); + } // Backbuffer is now bound. } CHECK_GL_ERROR_IF_DEBUG(); @@ -1755,10 +1758,6 @@ void GLQueueRunner::fbo_unbind() { bindDefaultFBO(); #endif - if (IsVRBuild()) { - BindVRFramebuffer(); - } - currentDrawHandle_ = 0; currentReadHandle_ = 0; CHECK_GL_ERROR_IF_DEBUG(); diff --git a/Common/GPU/OpenGL/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h index 1e009787ae..e9ad214eb4 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.h +++ b/Common/GPU/OpenGL/GLQueueRunner.h @@ -363,7 +363,7 @@ public: void RunInitSteps(const std::vector &steps, bool skipGLCalls); - void RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps = false); + void RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps, bool useVR); void LogSteps(const std::vector &steps); void CreateDeviceObjects(); diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 01cccb8874..f66b9b78fc 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -5,8 +5,6 @@ #include "Common/Thread/ThreadUtil.h" #include "Common/VR/PPSSPPVR.h" -#include "Core/Config.h" - #include "Common/Log.h" #include "Common/MemoryUtil.h" #include "Common/Math/math_util.h" @@ -356,9 +354,13 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende step->dependencies.insert(fb); } } + + if (invalidationCallback_) { + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); + } } -void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment) { +void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); _dbg_assert_(binding < MAX_GL_TEXTURE_SLOTS); GLRRenderData data{ GLRRenderCommand::BIND_FB_TEXTURE }; @@ -482,7 +484,6 @@ void GLRenderManager::BeginFrame() { // In GL, we have to do deletes on the submission thread. insideFrame_ = true; - renderStepOffset_ = 0; } void GLRenderManager::Finish() { @@ -579,18 +580,15 @@ void GLRenderManager::Run(int frame) { } } - if (IsVRBuild()) { - int passes = 1; - if (!IsMultiviewSupported() && g_Config.bEnableStereo) { - passes = 2; - } + if (IsVREnabled()) { + int passes = GetVRPassesCount(); for (int i = 0; i < passes; i++) { PreVRFrameRender(i); - queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1); + queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1, true); PostVRFrameRender(); } } else { - queueRunner_.RunSteps(stepsOnThread, skipGLCalls_); + queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, false, false); } stepsOnThread.clear(); @@ -617,9 +615,6 @@ void GLRenderManager::Run(int frame) { } void GLRenderManager::FlushSync() { - // TODO: Reset curRenderStep_? - renderStepOffset_ += (int)steps_.size(); - int curFrame = curFrame_; FrameData &frameData = frameData_[curFrame]; { diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 51d7e1e9eb..52ac971cec 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -10,6 +10,7 @@ #include #include "Common/GPU/OpenGL/GLCommon.h" +#include "Common/GPU/MiscTypes.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Log.h" #include "GLQueueRunner.h" @@ -98,12 +99,23 @@ struct GLRProgramFlags { bool useClipDistance2 : 1; }; +// Unless you manage lifetimes in some smart way, +// your loc data for uniforms and samplers need to be in a struct +// derived from this, and passed into CreateProgram. +class GLRProgramLocData { +public: + virtual ~GLRProgramLocData() {} +}; + class GLRProgram { public: ~GLRProgram() { if (program) { glDeleteProgram(program); } + if (locData_) { + delete locData_; + } } struct Semantic { int location; @@ -126,6 +138,8 @@ public: std::vector semantics_; std::vector queries_; std::vector initialize_; + + GLRProgramLocData *locData_; bool use_clip_distance[8]{}; struct UniformInfo { @@ -147,6 +161,7 @@ public: } return loc; } + std::unordered_map uniformCache_; }; @@ -368,6 +383,9 @@ public: GLRenderManager() {} ~GLRenderManager(); + void SetInvalidationCallback(InvalidationCallback callback) { + invalidationCallback_ = callback; + } void SetErrorCallback(ErrorCallbackFn callback, void *userdata) { queueRunner_.SetErrorCallback(callback, userdata); } @@ -434,13 +452,14 @@ public: // not be an active render pass. GLRProgram *CreateProgram( std::vector shaders, std::vector semantics, std::vector queries, - std::vector initializers, const GLRProgramFlags &flags) { + std::vector initializers, GLRProgramLocData *locData, const GLRProgramFlags &flags) { GLRInitStep step{ GLRInitStepType::CREATE_PROGRAM }; _assert_(shaders.size() <= ARRAY_SIZE(step.create_program.shaders)); step.create_program.program = new GLRProgram(); step.create_program.program->semantics_ = semantics; step.create_program.program->queries_ = queries; step.create_program.program->initialize_ = initializers; + step.create_program.program->locData_ = locData; step.create_program.program->use_clip_distance[0] = flags.useClipDistance0; step.create_program.program->use_clip_distance[1] = flags.useClipDistance1; step.create_program.program->use_clip_distance[2] = flags.useClipDistance2; @@ -462,7 +481,7 @@ public: return step.create_program.program; } - GLRInputLayout *CreateInputLayout(std::vector &entries) { + GLRInputLayout *CreateInputLayout(const std::vector &entries) { GLRInitStep step{ GLRInitStepType::CREATE_INPUT_LAYOUT }; step.create_input_layout.inputLayout = new GLRInputLayout(); step.create_input_layout.inputLayout->entries = entries; @@ -526,7 +545,7 @@ public: void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag); // Binds a framebuffer as a texture, for the following draws. - void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment); + void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit); bool CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); @@ -980,12 +999,6 @@ public: skipGLCalls_ = true; } - // Gets a frame-unique ID of the current step being recorded. Can be used to figure out - // when the current step has changed, which means the caller will need to re-record its state. - int GetCurrentStepId() const { - return renderStepOffset_ + (int)steps_.size(); - } - private: void BeginSubmitFrame(int frame); void EndSubmitFrame(int frame); @@ -1033,8 +1046,7 @@ private: // Submission time state bool insideFrame_ = false; - // This is the offset within this frame, in case of a mid-frame sync. - int renderStepOffset_ = 0; + GLRStep *curRenderStep_ = nullptr; std::vector steps_; std::vector initSteps_; @@ -1074,4 +1086,6 @@ private: GLRProgram *curProgram_ = nullptr; #endif Draw::DeviceCaps caps_{}; + + InvalidationCallback invalidationCallback_; }; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index bb937379ef..b7737bd919 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -10,6 +10,8 @@ #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Math/math_util.h" #include "Common/Math/lin/matrix4x4.h" +#include "Common/System/System.h" +#include "Common/Log.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/Shader.h" #include "Common/GPU/OpenGL/DataFormatGL.h" @@ -249,12 +251,21 @@ bool OpenGLShaderModule::Compile(GLRenderManager *render, ShaderLanguage languag if (source_.find("#version") == source_.npos) { source_ = ApplyGLSLPrelude(source_, glstage_); } + } else { + // Unsupported shader type + return false; } shader_ = render->CreateShader(glstage_, source_, tag_); + _assert_(shader_ != nullptr); // normally can't fail since we defer creation, unless there's a memory error or similar. return true; } +struct PipelineLocData : GLRProgramLocData { + GLint samplerLocs_[MAX_TEXTURE_SLOTS]{}; + std::vector dynamicUniformLocs_; +}; + class OpenGLInputLayout : public InputLayout { public: OpenGLInputLayout(GLRenderManager *render) : render_(render) {} @@ -276,10 +287,13 @@ public: for (auto &iter : shaders) { iter->Release(); } - if (program_) render_->DeleteProgram(program_); + if (program_) { + render_->DeleteProgram(program_); + } + // DO NOT delete locs_ here, it's deleted by the render manager. } - bool LinkShaders(); + bool LinkShaders(const PipelineDesc &desc); GLuint prim = 0; std::vector shaders; @@ -288,12 +302,14 @@ public: AutoRef blend; AutoRef raster; + // Not owned! + PipelineLocData *locs_ = nullptr; + // TODO: Optimize by getting the locations first and putting in a custom struct UniformBufferDesc dynamicUniforms; - GLint samplerLocs_[MAX_TEXTURE_SLOTS]{}; - std::vector dynamicUniformLocs_; GLRProgram *program_ = nullptr; + // Allow using other sampler names than sampler0, sampler1 etc in shaders. // If not set, will default to those, though. Slice samplers_; @@ -308,7 +324,7 @@ class OpenGLTexture; class OpenGLContext : public DrawContext { public: OpenGLContext(); - virtual ~OpenGLContext(); + ~OpenGLContext(); void SetTargetSize(int w, int h) override { DrawContext::SetTargetSize(w, h); @@ -355,10 +371,7 @@ public: // These functions should be self explanatory. void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return curRenderTarget_; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -400,7 +413,7 @@ public: curPipeline_->depthStencil->stencilPass); } - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int sampler, void *nativeTexture) override; void BindPipeline(Pipeline *pipeline) override; @@ -462,11 +475,11 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {} - int GetCurrentStepId() const override { - return renderManager_.GetCurrentStepId(); - } + void Invalidate(InvalidationFlags flags) override; - void InvalidateCachedState() override; + void SetInvalidationCallback(InvalidationCallback callback) override { + renderManager_.SetInvalidationCallback(callback); + } private: void ApplySamplers(); @@ -504,7 +517,7 @@ static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) { return (v1 << 16) | (v2 << 8) | v3; } -static bool HasIntelDualSrcBug(int versions[4]) { +static bool HasIntelDualSrcBug(const int versions[4]) { // Intel uses a confusing set of at least 3 version numbering schemes. This is the one given to OpenGL. switch (MakeIntelSimpleVer(versions[0], versions[1], versions[2])) { case MakeIntelSimpleVer(9, 17, 10): @@ -521,7 +534,6 @@ static bool HasIntelDualSrcBug(int versions[4]) { } OpenGLContext::OpenGLContext() { - // TODO: Detect more caps if (gl_extensions.IsGLES) { if (gl_extensions.OES_packed_depth_stencil || gl_extensions.OES_depth24) { caps_.preferredDepthBufferFormat = DataFormat::D24_S8; @@ -553,6 +565,7 @@ OpenGLContext::OpenGLContext() { caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported; caps_.depthClampSupported = gl_extensions.ARB_depth_clamp || gl_extensions.EXT_depth_clamp; caps_.blendMinMaxSupported = gl_extensions.EXT_blend_minmax; + caps_.multiSampleLevelsMask = 1; // More could be supported with some work. if (gl_extensions.IsGLES) { caps_.clipDistanceSupported = gl_extensions.EXT_clip_cull_distance || gl_extensions.APPLE_clip_distance; @@ -572,6 +585,7 @@ OpenGLContext::OpenGLContext() { } else { caps_.fragmentShaderDepthWriteSupported = true; } + caps_.fragmentShaderStencilWriteSupported = gl_extensions.ARB_shader_stencil_export; // GLES has no support for logic framebuffer operations. There doesn't even seem to exist any such extensions. caps_.logicOpSupported = !gl_extensions.IsGLES; @@ -596,6 +610,18 @@ OpenGLContext::OpenGLContext() { caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; } + + // Hide D3D9 when we know it likely won't work well. +#if PPSSPP_PLATFORM(WINDOWS) + caps_.supportsD3D9 = true; + if (!strcmp(gl_extensions.model, "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } +#endif + + // Very rough heuristic! + caps_.isTilingGPU = gl_extensions.IsGLES && caps_.vendor != GPUVendor::VENDOR_NVIDIA && caps_.vendor != GPUVendor::VENDOR_INTEL; + for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { frameData_[i].push = renderManager_.CreatePushBuffer(i, GL_ARRAY_BUFFER, 64 * 1024); } @@ -642,6 +668,15 @@ OpenGLContext::OpenGLContext() { bugs_.Infest(Bugs::PVR_GENMIPMAP_HEIGHT_GREATER); } + if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { +#if PPSSPP_PLATFORM(ANDROID) + // The bug seems to affect Adreno 3xx and 5xx, and appeared in Android 8.0 Oreo, so API 26. + // See https://github.com/hrydgard/ppsspp/issues/16015#issuecomment-1328316080. + if (gl_extensions.modelNumber < 600 && System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 26) + bugs_.Infest(Bugs::ADRENO_RESOURCE_DEADLOCK); +#endif + } + #if PPSSPP_PLATFORM(IOS) // For some reason, this bug does not appear on M1. if (caps_.vendor == GPUVendor::VENDOR_APPLE) { @@ -747,18 +782,20 @@ void OpenGLContext::EndFrame() { renderManager_.EndPushBuffer(frameData.push); // upload the data! renderManager_.Finish(); - InvalidateCachedState(); + Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } -void OpenGLContext::InvalidateCachedState() { - // Unbind stuff. - for (auto &texture : boundTextures_) { - texture = nullptr; +void OpenGLContext::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + // Unbind stuff. + for (auto &texture : boundTextures_) { + texture = nullptr; + } + for (auto &sampler : boundSamplers_) { + sampler = nullptr; + } + curPipeline_ = nullptr; } - for (auto &sampler : boundSamplers_) { - sampler = nullptr; - } - curPipeline_ = nullptr; } InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) { @@ -1055,7 +1092,7 @@ public: buffer_ = render->CreateBuffer(target_, size, usage_); totalSize_ = size; } - ~OpenGLBuffer() override { + ~OpenGLBuffer() { render_->DeleteBuffer(buffer_); } @@ -1112,10 +1149,10 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const } if (desc.uniformDesc) { pipeline->dynamicUniforms = *desc.uniformDesc; - pipeline->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size()); } + pipeline->samplers_ = desc.samplers; - if (pipeline->LinkShaders()) { + if (pipeline->LinkShaders(desc)) { // Build the rest of the virtual pipeline object. pipeline->prim = primToGL[(int)desc.prim]; pipeline->depthStencil = (OpenGLDepthStencilState *)desc.depthStencil; @@ -1130,7 +1167,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const } } -void OpenGLContext::BindTextures(int start, int count, Texture **textures) { +void OpenGLContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_TEXTURE_SLOTS); for (int i = start; i < start + count; i++) { OpenGLTexture *glTex = static_cast(textures[i - start]); @@ -1185,7 +1222,7 @@ ShaderModule *OpenGLContext::CreateShaderModule(ShaderStage stage, ShaderLanguag } } -bool OpenGLPipeline::LinkShaders() { +bool OpenGLPipeline::LinkShaders(const PipelineDesc &desc) { std::vector linkShaders; for (auto shaderModule : shaders) { if (shaderModule) { @@ -1216,32 +1253,38 @@ bool OpenGLPipeline::LinkShaders() { semantics.push_back({ SEM_POSITION, "a_position" }); semantics.push_back({ SEM_TEXCOORD0, "a_texcoord0" }); + locs_ = new PipelineLocData(); + locs_->dynamicUniformLocs_.resize(desc.uniformDesc->uniforms.size()); + std::vector queries; + int samplersToCheck; if (!samplers_.is_empty()) { for (int i = 0; i < (int)std::min((const uint32_t)samplers_.size(), MAX_TEXTURE_SLOTS); i++) { - queries.push_back({ &samplerLocs_[i], samplers_[i].name, true }); + queries.push_back({ &locs_->samplerLocs_[i], samplers_[i].name, true }); } + samplersToCheck = (int)samplers_.size(); } else { - queries.push_back({ &samplerLocs_[0], "sampler0" }); - queries.push_back({ &samplerLocs_[1], "sampler1" }); - queries.push_back({ &samplerLocs_[2], "sampler2" }); + queries.push_back({ &locs_->samplerLocs_[0], "sampler0" }); + queries.push_back({ &locs_->samplerLocs_[1], "sampler1" }); + queries.push_back({ &locs_->samplerLocs_[2], "sampler2" }); + samplersToCheck = 3; } _assert_(queries.size() <= MAX_TEXTURE_SLOTS); for (size_t i = 0; i < dynamicUniforms.uniforms.size(); ++i) { - queries.push_back({ &dynamicUniformLocs_[i], dynamicUniforms.uniforms[i].name }); + queries.push_back({ &locs_->dynamicUniformLocs_[i], dynamicUniforms.uniforms[i].name }); } std::vector initialize; for (int i = 0; i < MAX_TEXTURE_SLOTS; ++i) { - if (i < (int)samplers_.size()) { - initialize.push_back({ &samplerLocs_[i], 0, i }); + if (i < samplersToCheck) { + initialize.push_back({ &locs_->samplerLocs_[i], 0, i }); } else { - samplerLocs_[i] = -1; + locs_->samplerLocs_[i] = -1; } } GLRProgramFlags flags{}; - program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, flags); + program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, locs_, flags); return true; } @@ -1263,7 +1306,7 @@ void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { for (size_t i = 0; i < curPipeline_->dynamicUniforms.uniforms.size(); ++i) { const auto &uniform = curPipeline_->dynamicUniforms.uniforms[i]; - const GLint &loc = curPipeline_->dynamicUniformLocs_[i]; + const GLint &loc = curPipeline_->locs_->dynamicUniformLocs_[i]; const float *data = (const float *)((uint8_t *)ub + uniform.offset); switch (uniform.type) { case UniformType::FLOAT1: @@ -1390,6 +1433,9 @@ void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) { Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) { CheckGLExtensions(); + // TODO: Support multiview later. (It's our only use case for multi layers). + _dbg_assert_(desc.numLayers == 1); + GLRFramebuffer *framebuffer = renderManager_.CreateFramebuffer(desc.width, desc.height, desc.z_stencil); OpenGLFramebuffer *fbo = new OpenGLFramebuffer(&renderManager_, framebuffer); return fbo; @@ -1436,7 +1482,7 @@ bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, in return true; } -void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int color) { +void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; _assert_(binding < MAX_TEXTURE_SLOTS); @@ -1453,7 +1499,7 @@ void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBCh aspect |= GL_STENCIL_BUFFER_BIT; boundTextures_[binding] = &fb->framebuffer_->z_stencil_texture; } - renderManager_.BindFramebufferAsTexture(fb->framebuffer_, binding, aspect, color); + renderManager_.BindFramebufferAsTexture(fb->framebuffer_, binding, aspect); } void OpenGLContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { @@ -1499,6 +1545,13 @@ uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const { case DataFormat::R8_UNORM: return FMT_TEXTURE; + case DataFormat::R16_UNORM: + if (!gl_extensions.IsGLES) { + return FMT_TEXTURE; + } else { + return 0; + } + break; case DataFormat::BC1_RGBA_UNORM_BLOCK: case DataFormat::BC2_UNORM_BLOCK: diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 75e1a9b2e9..6e29445734 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -4,9 +4,12 @@ #include #include // for size_t +#include "Common/Common.h" + // GLSL_1xx and GLSL_3xx each cover a lot of sub variants. All the little quirks // that differ are covered in ShaderLanguageDesc. // Defined as a bitmask so stuff like GetSupportedShaderLanguages can return combinations. +// TODO: We can probably move away from this distinction soon, now that we mostly generate/translate shaders. enum ShaderLanguage { GLSL_1xx = 1, GLSL_3xx = 2, @@ -30,7 +33,6 @@ enum class ShaderStage { const char *ShaderStageAsString(ShaderStage lang); - struct ShaderLanguageDesc { ShaderLanguageDesc() {} explicit ShaderLanguageDesc(ShaderLanguage lang); @@ -91,12 +93,18 @@ struct UniformDef { int index; }; +enum class SamplerFlags { + ARRAY_ON_VULKAN = 1, +}; +ENUM_CLASS_BITOPS(SamplerFlags); + struct SamplerDef { + int binding; // Might only be used by some backends. const char *name; + SamplerFlags flags; // TODO: Might need unsigned samplers, 3d samplers, or other types in the future. }; - // For passing error messages from shader compilation (and other critical issues) back to the host. // This can run on any thread - be aware! // TODO: See if we can find a less generic name for this. diff --git a/Common/GPU/ShaderTranslation.cpp b/Common/GPU/ShaderTranslation.cpp index 9391d1b7da..732ef68633 100644 --- a/Common/GPU/ShaderTranslation.cpp +++ b/Common/GPU/ShaderTranslation.cpp @@ -98,7 +98,7 @@ R"(#version 450 )"; static const char *vulkanUboDecl = R"( -layout (std140, set = 0, binding = 0) uniform Data { +layout (std140, set = 1, binding = 0) uniform Data { vec2 u_texelDelta; vec2 u_pixelDelta; vec4 u_time; @@ -187,11 +187,11 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada continue; } else if (line.find("uniform sampler2D") == 0) { if (sscanf(line.c_str(), "uniform sampler2D sampler%d", &num) == 1) - line = StringFromFormat("layout(set = 0, binding = %d) ", num + 1) + line; + line = StringFromFormat("layout(set = 1, binding = %d) ", num + 1) + line; else if (line.find("sampler0") != line.npos) - line = "layout(set = 0, binding = 1) " + line; + line = "layout(set = 1, binding = 1) " + line; else - line = "layout(set = 0, binding = 2) " + line; + line = "layout(set = 1, binding = 2) " + line; } else if (line.find("uniform ") != std::string::npos) { continue; } else if (2 == sscanf(line.c_str(), "varying vec%d v_texcoord%d;", &vecSize, &num)) { diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 7ca6deaeb0..01132b11de 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -7,7 +7,6 @@ #include "Common/Log.h" const char * const vulkan_glsl_preamble_fs = -"#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" "#extension GL_ARB_conservative_depth : enable\n" @@ -45,7 +44,6 @@ static const char * const hlsl_d3d9_preamble_fs = "#define DISCARD_BELOW(x) clip(x)\n"; static const char * const vulkan_glsl_preamble_vs = -"#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" "#define mul(x, y) ((x) * (y))\n" @@ -69,7 +67,6 @@ static const char * const hlsl_preamble_gs = "\n"; static const char * const vulkan_glsl_preamble_gs = -"#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" "#define mul(x, y) ((x) * (y))\n" @@ -113,9 +110,17 @@ ShaderWriter & ShaderWriter::F(const char *format, ...) { return *this; } -void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions) { +void ShaderWriter::Preamble(Slice extensions) { switch (lang_.shaderLanguage) { case GLSL_VULKAN: + C("#version 450\n"); + if (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) { + C("#extension GL_EXT_multiview : enable\n"); + } + // IMPORTANT! Extensions must be the first thing after #version. + for (size_t i = 0; i < extensions.size(); i++) { + F("%s\n", extensions[i]); + } switch (stage_) { case ShaderStage::Vertex: W(vulkan_glsl_preamble_vs); @@ -154,8 +159,8 @@ void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions default: // OpenGL F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : ""); // IMPORTANT! Extensions must be the first thing after #version. - for (size_t i = 0; i < num_gl_extensions; i++) { - F("%s\n", gl_extensions[i]); + for (size_t i = 0; i < extensions.size(); i++) { + F("%s\n", extensions[i]); } // Print some system info - useful to gather information directly from screenshots. if (strlen(lang_.driverInfo) != 0) { @@ -250,7 +255,7 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform } } -void ShaderWriter::BeginFSMain(Slice uniforms, Slice varyings, FSFlags flags) { +void ShaderWriter::BeginFSMain(Slice uniforms, Slice varyings) { _assert_(this->stage_ == ShaderStage::Fragment); switch (lang_.shaderLanguage) { case HLSL_D3D11: @@ -264,13 +269,13 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var C("};\n"); } - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C("float gl_FragDepth;\n"); } C("struct PS_OUT {\n"); C(" vec4 target : SV_Target0;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float depth : SV_Depth;\n"); } C("};\n"); @@ -285,14 +290,14 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var F(") {\n"); C(" PS_OUT ps_out;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float gl_FragDepth;\n"); } break; case HLSL_D3D9: C("struct PS_OUT {\n"); C(" vec4 target : SV_Target0;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float depth : DEPTH;\n"); } C("};\n"); @@ -310,7 +315,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var F(") {\n"); C(" PS_OUT ps_out;\n"); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" float gl_FragDepth;\n"); } @@ -321,7 +326,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var } C("layout(location = 0, index = 0) out vec4 fragColor0;\n"); if (!uniforms.is_empty()) { - C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n"); + C("layout(std140, set = 1, binding = 0) uniform bufferVals {\n"); for (auto &uniform : uniforms) { F("%s %s;\n", uniform.type, uniform.name); } @@ -404,13 +409,13 @@ void ShaderWriter::EndVSMain(Slice varyings) { C("}\n"); } -void ShaderWriter::EndFSMain(const char *vec4_color_variable, FSFlags flags) { +void ShaderWriter::EndFSMain(const char *vec4_color_variable) { _assert_(this->stage_ == ShaderStage::Fragment); switch (lang_.shaderLanguage) { case HLSL_D3D11: case HLSL_D3D9: F(" ps_out.target = %s;\n", vec4_color_variable); - if (flags & FSFLAG_WRITEDEPTH) { + if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) { C(" ps_out.depth = gl_FragDepth;\n"); } C(" return ps_out;\n"); @@ -454,34 +459,43 @@ void ShaderWriter::ConstFloat(const char *name, float value) { void ShaderWriter::DeclareSamplers(Slice samplers) { for (int i = 0; i < (int)samplers.size(); i++) { - DeclareTexture2D(samplers[i].name, i); - DeclareSampler2D(samplers[i].name, i); + DeclareTexture2D(samplers[i]); + DeclareSampler2D(samplers[i]); } + samplerDefs_ = samplers; } -void ShaderWriter::DeclareTexture2D(const char *name, int binding) { +void ShaderWriter::ApplySamplerMetadata(Slice samplers) { + samplerDefs_ = samplers; +} + +void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { switch (lang_.shaderLanguage) { case HLSL_D3D11: - F("Texture2D %s : register(t%d);\n", name, binding); + F("Texture2D %s : register(t%d);\n", def.name, def.binding); break; case HLSL_D3D9: - F("sampler %s: register(s%d);\n", name, binding); + F("sampler %s: register(s%d);\n", def.name, def.binding); break; case GLSL_VULKAN: - // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. - F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", binding + 1, name); + // texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1. + if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) { + F("layout(set = 1, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); + } else { + F("layout(set = 1, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); + } break; default: - F("uniform sampler2D %s;\n", name); + F("uniform sampler2D %s;\n", def.name); break; } } -void ShaderWriter::DeclareSampler2D(const char *name, int binding) { +void ShaderWriter::DeclareSampler2D(const SamplerDef &def) { // We only use separate samplers in HLSL D3D11, where we have no choice. switch (lang_.shaderLanguage) { case HLSL_D3D11: - F("SamplerState %sSamp : register(s%d);\n", name, binding); + F("SamplerState %sSamp : register(s%d);\n", def.name, def.binding); break; default: break; @@ -489,6 +503,7 @@ void ShaderWriter::DeclareSampler2D(const char *name, int binding) { } ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv) { + const SamplerDef *samp = GetSamplerDef(sampName); switch (lang_.shaderLanguage) { case HLSL_D3D11: F("%s.Sample(%sSamp, %s)", sampName, sampName, uv); @@ -498,13 +513,20 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - F("%s(%s, %s)", lang_.texture, sampName, uv); + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) { + const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; + F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index); + } else { + F("%s(%s, %s)", lang_.texture, sampName, uv); + } break; } return *this; } ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const char *uv, int offX, int offY) { + const SamplerDef *samp = GetSamplerDef(sampName); + switch (lang_.shaderLanguage) { case HLSL_D3D11: F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY); @@ -515,13 +537,20 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY); + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) { + const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0"; + F("%sOffset(%s, vec3(%s, %s), ivec2(%d, %d))", lang_.texture, sampName, uv, index, offX, offY); + } else { + F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY); + } break; } return *this; } ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, int level) { + const SamplerDef *samp = GetSamplerDef(sampName); + switch (lang_.shaderLanguage) { case HLSL_D3D11: F("%s.Load(ivec3(%s, %d))", sampName, uv, level); @@ -532,7 +561,12 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, break; default: // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. - F("texelFetch(%s, %s, %d)", sampName, uv, level); + if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) { + const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "gl_ViewIndex" : "0"; + F("texelFetch(%s, vec3(%s, %s), %d)", sampName, uv, index, level); + } else { + F("texelFetch(%s, %s, %d)", sampName, uv, level); + } break; } return *this; @@ -553,3 +587,12 @@ ShaderWriter &ShaderWriter::GetTextureSize(const char *szVariable, const char *t } return *this; } + +const SamplerDef *ShaderWriter::GetSamplerDef(const char *name) const { + for (int i = 0; i < (int)samplerDefs_.size(); i++) { + if (!strcmp(samplerDefs_[i].name, name)) { + return &samplerDefs_[i]; + } + } + return nullptr; +} diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 50f3bb1f0d..379e704319 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -30,15 +30,19 @@ struct VaryingDef { const char *precision; }; -enum FSFlags { - FSFLAG_NONE = 0, - FSFLAG_WRITEDEPTH = 1, +enum class ShaderWriterFlags { + NONE = 0, + FS_WRITE_DEPTH = 1, + FS_AUTO_STEREO = 2, // Automatically indexes makes samplers tagged with `array` by gl_ViewIndex. Useful for stereo rendering. }; +ENUM_CLASS_BITOPS(ShaderWriterFlags); class ShaderWriter { public: - ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions = nullptr, size_t num_gl_extensions = 0) : p_(buffer), lang_(lang), stage_(stage) { - Preamble(gl_extensions, num_gl_extensions); + // Extensions are supported for both OpenGL ES and Vulkan (though of course, they're different). + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice extensions = Slice(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage), flags_(flags) { + buffer[0] = '\0'; + Preamble(extensions); } ShaderWriter(const ShaderWriter &) = delete; @@ -73,9 +77,16 @@ public: void HighPrecisionFloat(); void LowPrecisionFloat(); + // NOTE: samplers must live for the rest of ShaderWriter's lifetime. No way to express that in C++ though :( void DeclareSamplers(Slice samplers); + // Same as DeclareSamplers, but doesn't actually declare them. + // This is currently only required by FragmentShaderGenerator. + void ApplySamplerMetadata(Slice samplers); + void ConstFloat(const char *name, float value); + void SetFlags(ShaderWriterFlags flags) { flags_ |= flags; } + void SetTexBindingBase(int base) { texBindingBase_ = base; } ShaderWriter &SampleTexture2D(const char *texName, const char *uv); ShaderWriter &SampleTexture2DOffset(const char *texName, const char *uv, int offX, int offY); @@ -84,12 +95,12 @@ public: // Simple shaders with no special tricks. void BeginVSMain(Slice inputs, Slice uniforms, Slice varyings); - void BeginFSMain(Slice uniforms, Slice varyings, FSFlags flags); + void BeginFSMain(Slice uniforms, Slice varyings); void BeginGSMain(Slice varyings, Slice outVaryings); // For simple shaders that output a single color, we can deal with this generically. void EndVSMain(Slice varyings); - void EndFSMain(const char *vec4_color_variable, FSFlags flags); + void EndFSMain(const char *vec4_color_variable); void EndGSMain(); const ShaderLanguageDesc &Lang() const { @@ -107,12 +118,17 @@ public: private: // Several of the shader languages ignore samplers, beware of that. - void DeclareSampler2D(const char *name, int binding); - void DeclareTexture2D(const char *name, int binding); + void DeclareSampler2D(const SamplerDef &def); + void DeclareTexture2D(const SamplerDef &def); + const SamplerDef *GetSamplerDef(const char *name) const; - void Preamble(const char **gl_extensions, size_t num_gl_extensions); + void Preamble(Slice extensions); char *p_; const ShaderLanguageDesc &lang_; const ShaderStage stage_; + Slice samplers_; + ShaderWriterFlags flags_ = ShaderWriterFlags::NONE; + Slice samplerDefs_; + int texBindingBase_ = 1; }; diff --git a/Common/GPU/Vulkan/VulkanBarrier.cpp b/Common/GPU/Vulkan/VulkanBarrier.cpp index e4f2d09089..d47f506845 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.cpp +++ b/Common/GPU/Vulkan/VulkanBarrier.cpp @@ -9,4 +9,5 @@ void VulkanBarrier::Flush(VkCommandBuffer cmd) { imageBarriers_.clear(); srcStageMask_ = 0; dstStageMask_ = 0; + dependencyFlags_ = 0; } diff --git a/Common/GPU/Vulkan/VulkanBarrier.h b/Common/GPU/Vulkan/VulkanBarrier.h index 19edc548ba..1fefb5adfa 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.h +++ b/Common/GPU/Vulkan/VulkanBarrier.h @@ -14,7 +14,7 @@ class VulkanContext; class VulkanBarrier { public: void TransitionImage( - VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask, + VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask @@ -36,7 +36,7 @@ public: imageBarrier.subresourceRange.aspectMask = aspectMask; imageBarrier.subresourceRange.baseMipLevel = baseMip; imageBarrier.subresourceRange.levelCount = numMipLevels; - imageBarrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. + imageBarrier.subresourceRange.layerCount = numLayers; // NOTE: We could usually use VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS, but really old Mali drivers have problems with those. imageBarrier.subresourceRange.baseArrayLayer = 0; imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -46,7 +46,7 @@ public: // Automatically determines access and stage masks from layouts. // Not universally usable, but works for PPSSPP's use. void TransitionImageAuto( - VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout + VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout ) { _dbg_assert_(image != VK_NULL_HANDLE); @@ -104,7 +104,7 @@ public: imageBarrier.subresourceRange.aspectMask = aspectMask; imageBarrier.subresourceRange.baseMipLevel = baseMip; imageBarrier.subresourceRange.levelCount = numMipLevels; - imageBarrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. + imageBarrier.subresourceRange.layerCount = numLayers; // NOTE: We could usually use VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS, but really old Mali drivers have problems with those. imageBarrier.subresourceRange.baseArrayLayer = 0; imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index 937276d10f..8e523d0bf2 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -57,7 +57,7 @@ std::string VulkanVendorString(uint32_t vendorId) { case VULKAN_VENDOR_ARM: return "ARM"; case VULKAN_VENDOR_QUALCOMM: return "Qualcomm"; case VULKAN_VENDOR_IMGTEC: return "Imagination"; - + case VULKAN_VENDOR_APPLE: return "Apple"; default: return StringFromFormat("%08x", vendorId); } @@ -253,15 +253,21 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { VkPhysicalDeviceProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; VkPhysicalDevicePushDescriptorPropertiesKHR pushProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR}; VkPhysicalDeviceExternalMemoryHostPropertiesEXT extHostMemProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT}; + VkPhysicalDeviceDepthStencilResolveProperties depthStencilResolveProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES}; + props2.pNext = &pushProps; pushProps.pNext = &extHostMemProps; + extHostMemProps.pNext = &depthStencilResolveProps; vkGetPhysicalDeviceProperties2KHR(physical_devices_[i], &props2); // Don't want bad pointers sitting around. props2.pNext = nullptr; pushProps.pNext = nullptr; + extHostMemProps.pNext = nullptr; + depthStencilResolveProps.pNext = nullptr; physicalDeviceProperties_[i].properties = props2.properties; physicalDeviceProperties_[i].pushDescriptorProperties = pushProps; physicalDeviceProperties_[i].externalMemoryHostProperties = extHostMemProps; + physicalDeviceProperties_[i].depthStencilResolve = depthStencilResolveProps; } } else { for (uint32_t i = 0; i < gpu_count; i++) { @@ -329,7 +335,7 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem for (uint32_t i = 0; i < 32; i++) { if ((typeBits & 1) == 1) { // Type is available, does it match user properties? - if ((memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { + if ((memory_properties_.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { *typeIndex = i; return true; } @@ -569,38 +575,48 @@ void VulkanContext::ChooseDevice(int physical_device) { } // This is as good a place as any to do this. - vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); - INFO_LOG(G3D, "Memory Types (%d):", memory_properties.memoryTypeCount); - for (int i = 0; i < (int)memory_properties.memoryTypeCount; i++) { + vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties_); + INFO_LOG(G3D, "Memory Types (%d):", memory_properties_.memoryTypeCount); + for (int i = 0; i < (int)memory_properties_.memoryTypeCount; i++) { // Don't bother printing dummy memory types. - if (!memory_properties.memoryTypes[i].propertyFlags) + if (!memory_properties_.memoryTypes[i].propertyFlags) continue; - INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", - (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : ""); + INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties_.memoryTypes[i].heapIndex, + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", + (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : ""); } // Optional features if (extensionsLookup_.KHR_get_physical_device_properties2) { VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR}; + // Add to chain even if not supported, GetPhysicalDeviceFeatures is supposed to ignore unknown structs. + VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; + features2.pNext = &multiViewFeatures; vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2); - deviceFeatures_.available = features2.features; + deviceFeatures_.available.standard = features2.features; + deviceFeatures_.available.multiview = multiViewFeatures; } else { - vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available); + vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard); + deviceFeatures_.available.multiview = {}; } deviceFeatures_.enabled = {}; // Enable a few safe ones if they are available. - deviceFeatures_.enabled.dualSrcBlend = deviceFeatures_.available.dualSrcBlend; - deviceFeatures_.enabled.logicOp = deviceFeatures_.available.logicOp; - deviceFeatures_.enabled.depthClamp = deviceFeatures_.available.depthClamp; - deviceFeatures_.enabled.depthBounds = deviceFeatures_.available.depthBounds; - deviceFeatures_.enabled.samplerAnisotropy = deviceFeatures_.available.samplerAnisotropy; - deviceFeatures_.enabled.shaderClipDistance = deviceFeatures_.available.shaderClipDistance; - deviceFeatures_.enabled.shaderCullDistance = deviceFeatures_.available.shaderCullDistance; - deviceFeatures_.enabled.geometryShader = deviceFeatures_.available.geometryShader; + deviceFeatures_.enabled.standard.dualSrcBlend = deviceFeatures_.available.standard.dualSrcBlend; + deviceFeatures_.enabled.standard.logicOp = deviceFeatures_.available.standard.logicOp; + deviceFeatures_.enabled.standard.depthClamp = deviceFeatures_.available.standard.depthClamp; + deviceFeatures_.enabled.standard.depthBounds = deviceFeatures_.available.standard.depthBounds; + deviceFeatures_.enabled.standard.samplerAnisotropy = deviceFeatures_.available.standard.samplerAnisotropy; + deviceFeatures_.enabled.standard.shaderClipDistance = deviceFeatures_.available.standard.shaderClipDistance; + deviceFeatures_.enabled.standard.shaderCullDistance = deviceFeatures_.available.standard.shaderCullDistance; + deviceFeatures_.enabled.standard.geometryShader = deviceFeatures_.available.standard.geometryShader; + deviceFeatures_.enabled.standard.sampleRateShading = deviceFeatures_.available.standard.sampleRateShading; + + deviceFeatures_.enabled.multiview = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; + deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview; + // deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader; GetDeviceLayerExtensionList(nullptr, device_extension_properties_); @@ -671,6 +687,8 @@ VkResult VulkanContext::CreateDevice() { extensionsLookup_.EXT_fragment_shader_interlock = EnableDeviceExtension(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME); extensionsLookup_.ARM_rasterization_order_attachment_access = EnableDeviceExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME); + VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_info.queueCreateInfoCount = 1; device_info.pQueueCreateInfos = &queue_info; @@ -678,7 +696,14 @@ VkResult VulkanContext::CreateDevice() { device_info.ppEnabledLayerNames = device_info.enabledLayerCount ? device_layer_names_.data() : nullptr; device_info.enabledExtensionCount = (uint32_t)device_extensions_enabled_.size(); device_info.ppEnabledExtensionNames = device_info.enabledExtensionCount ? device_extensions_enabled_.data() : nullptr; - device_info.pEnabledFeatures = &deviceFeatures_.enabled; + + if (extensionsLookup_.KHR_get_physical_device_properties2) { + device_info.pNext = &features2; + features2.features = deviceFeatures_.enabled.standard; + features2.pNext = &deviceFeatures_.enabled.multiview; + } else { + device_info.pEnabledFeatures = &deviceFeatures_.enabled.standard; + } VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_); if (res != VK_SUCCESS) { @@ -1084,9 +1109,14 @@ bool VulkanContext::InitSwapchain() { std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform); g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); + + uint32_t allowedRotations = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + // Hack: Don't allow 270 degrees pretransform (inverse landscape), it creates bizarre issues on some devices (see #15773). + allowedRotations &= ~VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + if (surfCapabilities_.currentTransform & (VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) { preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - } else if (surfCapabilities_.currentTransform & (VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR)) { + } else if (surfCapabilities_.currentTransform & allowedRotations) { // Normal, sensible rotations. Let's handle it. preTransform = surfCapabilities_.currentTransform; g_display_rot_matrix.setIdentity(); @@ -1109,20 +1139,29 @@ bool VulkanContext::InitSwapchain() { _dbg_assert_(false); } } else { - // Let the OS rotate the image (potentially slow on many Android devices) + // Let the OS rotate the image (potentially slower on many Android devices) preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } std::string preTransformStr = surface_transforms_to_string(preTransform); - INFO_LOG(G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) { - INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!)"); - // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). - // To keep the size consistent even with pretransform, do this after the swap. Should be fine. - // This is fixed in newer PowerVR drivers but I don't know the cutoff. - swapChainExtent_.width &= ~31; + u32 driverVersion = physicalDeviceProperties_[physical_device_].properties.driverVersion; + // Cutoff the hack at driver version 1.386.1368 (0x00582558, see issue #15773). + if (driverVersion < 0x00582558) { + INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!) driverVersion=%08x", driverVersion); + // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). + // To keep the size consistent even with pretransform, do this after the swap. Should be fine. + // This is fixed in newer PowerVR drivers but I don't know the cutoff. + swapChainExtent_.width &= ~31; + + // TODO: Also modify display_xres/display_yres appropriately for scissors to match. + // This will get a bit messy. Ideally we should remove that logic from app-android.cpp + // and move it here, but the OpenGL code still needs it. + } else { + INFO_LOG(G3D, "PowerVR driver version new enough (%08x), not applying swapchain width hack", driverVersion); + } } VkSwapchainCreateInfoKHR swap_chain_info{ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; @@ -1227,7 +1266,7 @@ bool VulkanContext::CreateShaderModule(const std::vector &spirv, VkSha } } -void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask, +void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) { @@ -1240,7 +1279,7 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int image_memory_barrier.subresourceRange.aspectMask = aspectMask; image_memory_barrier.subresourceRange.baseMipLevel = baseMip; image_memory_barrier.subresourceRange.levelCount = numMipLevels; - image_memory_barrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. + image_memory_barrier.subresourceRange.layerCount = numLayers; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); @@ -1354,37 +1393,6 @@ void finalize_glslang() { glslang::FinalizeProcess(); } -const char *VulkanResultToString(VkResult res) { - switch (res) { - case VK_NOT_READY: return "VK_NOT_READY"; - case VK_TIMEOUT: return "VK_TIMEOUT"; - case VK_EVENT_SET: return "VK_EVENT_SET"; - case VK_EVENT_RESET: return "VK_EVENT_RESET"; - case VK_INCOMPLETE: return "VK_INCOMPLETE"; - case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; - case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; - case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST"; - case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED"; - case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT"; - case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT"; - case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT"; - case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; - case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; - case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; - case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; - case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; - case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; - case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; - - default: - return "VK_ERROR_...(unknown)"; - } -} - void VulkanDeleteList::Take(VulkanDeleteList &del) { _dbg_assert_(cmdPools_.empty()); _dbg_assert_(descPools_.empty()); diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index fb98b5a0db..464b78a47d 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -35,6 +35,7 @@ enum { VULKAN_VENDOR_ARM = 0x000013B5, // Mali VULKAN_VENDOR_QUALCOMM = 0x00005143, VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR + VULKAN_VENDOR_APPLE = 0x0000106b, // Apple through MoltenVK }; VK_DEFINE_HANDLE(VmaAllocator); @@ -222,6 +223,9 @@ public: SetDebugNameImpl((uint64_t)handle, type, name); } } + bool DebugLayerEnabled() const { + return extensionsLookup_.EXT_debug_utils; + } bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); @@ -250,6 +254,12 @@ public: VkPhysicalDeviceProperties properties; VkPhysicalDevicePushDescriptorPropertiesKHR pushDescriptorProperties; VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProperties; + VkPhysicalDeviceDepthStencilResolveProperties depthStencilResolve; + }; + + struct AllPhysicalDeviceFeatures { + VkPhysicalDeviceFeatures standard; + VkPhysicalDeviceMultiviewFeatures multiview; }; const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const { @@ -275,9 +285,13 @@ public: return device_extensions_enabled_; } + const VkPhysicalDeviceMemoryProperties &GetMemoryProperties() const { + return memory_properties_; + } + struct PhysicalDeviceFeatures { - VkPhysicalDeviceFeatures available{}; - VkPhysicalDeviceFeatures enabled{}; + AllPhysicalDeviceFeatures available{}; + AllPhysicalDeviceFeatures enabled{}; }; const PhysicalDeviceFeatures &GetDeviceFeatures() const { return deviceFeatures_; } @@ -393,7 +407,8 @@ private: uint32_t graphics_queue_family_index_ = -1; std::vector physicalDeviceProperties_; std::vector queueFamilyProperties_; - VkPhysicalDeviceMemoryProperties memory_properties{}; + + VkPhysicalDeviceMemoryProperties memory_properties_{}; // Custom collection of things that are good to know VulkanPhysicalDeviceInfo deviceInfo_{}; @@ -436,7 +451,7 @@ private: }; // Detailed control. -void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, VkImageAspectFlags aspectMask, +void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, int numLayers, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); @@ -453,7 +468,6 @@ enum class GLSLVariant { bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *sourceCode, GLSLVariant variant, std::vector &spirv, std::string *errorMessage); -const char *VulkanResultToString(VkResult res); const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace); const char *VulkanFormatToString(VkFormat format); diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp index 83b3d974c0..7a3d3a079f 100644 --- a/Common/GPU/Vulkan/VulkanDebug.cpp +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -42,6 +42,12 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( // UNASSIGNED return false; } + if (messageCode == 606910136 || messageCode == -392708513 || messageCode == -384083808) { + // VUID-vkCmdDraw-None-02686 + // Kinda false positive, or at least very unnecessary, now that I solved the real issue. + // See https://github.com/hrydgard/ppsspp/pull/16354 + return false; + } if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { message << "ERROR("; @@ -86,6 +92,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( } else { WARN_LOG(G3D, "VKDEBUG: %s", msg.c_str()); } + // false indicates that layer should not bail-out of an // API call that had validation failures. This may mean that the // app dies inside the driver due to invalid parameter(s). diff --git a/Common/GPU/Vulkan/VulkanFrameData.cpp b/Common/GPU/Vulkan/VulkanFrameData.cpp index ab74478396..4503ea1c82 100644 --- a/Common/GPU/Vulkan/VulkanFrameData.cpp +++ b/Common/GPU/Vulkan/VulkanFrameData.cpp @@ -121,7 +121,7 @@ VkCommandBuffer FrameData::GetInitCmd(VulkanContext *vulkan) { } void FrameData::SubmitPending(VulkanContext *vulkan, FrameSubmitType type, FrameDataShared &sharedData) { - VkCommandBuffer cmdBufs[2]; + VkCommandBuffer cmdBufs[3]; int numCmdBufs = 0; VkFence fenceToTrigger = VK_NULL_HANDLE; diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp new file mode 100644 index 0000000000..ec50e3f7a4 --- /dev/null +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -0,0 +1,536 @@ +#include "Common/StringUtils.h" +#include "Common/GPU/Vulkan/VulkanFramebuffer.h" +#include "Common/GPU/Vulkan/VulkanQueueRunner.h" + +VkSampleCountFlagBits MultiSampleLevelToFlagBits(int count) { + // TODO: Check hardware support here, or elsewhere? + // Some hardware only supports 4x. + switch (count) { + case 0: return VK_SAMPLE_COUNT_1_BIT; + case 1: return VK_SAMPLE_COUNT_2_BIT; + case 2: return VK_SAMPLE_COUNT_4_BIT; // The only non-1 level supported on some mobile chips. + case 3: return VK_SAMPLE_COUNT_8_BIT; + case 4: return VK_SAMPLE_COUNT_16_BIT; // rare but exists, on Intel for example + default: + _assert_(false); + return VK_SAMPLE_COUNT_1_BIT; + } +} + +void VKRImage::Delete(VulkanContext *vulkan) { + // Get rid of the views first, feels cleaner (but in reality doesn't matter). + if (rtView) + vulkan->Delete().QueueDeleteImageView(rtView); + if (texAllLayersView) + vulkan->Delete().QueueDeleteImageView(texAllLayersView); + for (int i = 0; i < 2; i++) { + if (texLayerViews[i]) { + vulkan->Delete().QueueDeleteImageView(texLayerViews[i]); + } + } + + if (image) { + _dbg_assert_(alloc); + vulkan->Delete().QueueDeleteImageAllocation(image, alloc); + } +} + +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag) + : vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) { + + _dbg_assert_(tag); + + CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + if (createDepthStencilBuffer) { + CreateImage(vulkan_, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + } + + if (_multiSampleLevel > 0) { + sampleCount = MultiSampleLevelToFlagBits(_multiSampleLevel); + + // TODO: Create a different tag for these? + CreateImage(vulkan_, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); + if (createDepthStencilBuffer) { + CreateImage(vulkan_, initCmd, msaaDepth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); + } + } else { + sampleCount = VK_SAMPLE_COUNT_1_BIT; + } + + UpdateTag(tag); + + // We create the actual framebuffer objects on demand, because some combinations might not make sense. + // Framebuffer objects are just pointers to a set of images, so no biggie. +} + +void VKRFramebuffer::UpdateTag(const char *newTag) { + char name[128]; + snprintf(name, sizeof(name), "fb_color_%s", tag_.c_str()); + vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, name); + vulkan_->SetDebugName(color.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + if (depth.image) { + snprintf(name, sizeof(name), "fb_depth_%s", tag_.c_str()); + vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name); + vulkan_->SetDebugName(depth.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + } + for (size_t rpType = 0; rpType < (size_t)RenderPassType::TYPE_COUNT; rpType++) { + if (framebuf[rpType]) { + snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); + vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); + } + } +} + +VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) { + bool multiview = RenderPassTypeHasMultiView(rpType); + + if (framebuf[(int)rpType]) { + return framebuf[(int)rpType]; + } + + VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + VkImageView views[4]{}; + + bool hasDepth = RenderPassTypeHasDepth(rpType); + int attachmentCount = 0; + views[attachmentCount++] = color.rtView; // 2D array texture if multilayered. + if (hasDepth) { + if (!depth.rtView) { + WARN_LOG(G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", depth.image, depth.texAllLayersView, depth.format, tag_.c_str(), width, height); + // Will probably crash, depending on driver. + } + views[attachmentCount++] = depth.rtView; + } + if (rpType & RenderPassType::MULTISAMPLE) { + views[attachmentCount++] = msaaColor.rtView; + if (hasDepth) { + views[attachmentCount++] = msaaDepth.rtView; + } + } + + fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType, sampleCount); + fbci.attachmentCount = attachmentCount; + fbci.pAttachments = views; + fbci.width = width; + fbci.height = height; + fbci.layers = 1; // With multiview, this should be set as 1. + + VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]); + _assert_(res == VK_SUCCESS); + + if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) { + vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str()); + } + + return framebuf[(int)rpType]; +} + +VKRFramebuffer::~VKRFramebuffer() { + color.Delete(vulkan_); + depth.Delete(vulkan_); + msaaColor.Delete(vulkan_); + msaaDepth.Delete(vulkan_); + + for (auto &fb : framebuf) { + if (fb) { + vulkan_->Delete().QueueDeleteFramebuffer(fb); + } + } +} + +// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture. +// This requires a different sampling path! +void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { + // We don't support more exotic layer setups for now. Mono or stereo. + _dbg_assert_(numLayers == 1 || numLayers == 2); + + VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + ici.arrayLayers = numLayers; + ici.mipLevels = 1; + ici.extent.width = width; + ici.extent.height = height; + ici.extent.depth = 1; + ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + ici.imageType = VK_IMAGE_TYPE_2D; + ici.samples = sampleCount; + ici.tiling = VK_IMAGE_TILING_OPTIMAL; + ici.format = format; + ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + if (sampleCount == VK_SAMPLE_COUNT_1_BIT) { + ici.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + } + if (color) { + ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (sampleCount == VK_SAMPLE_COUNT_1_BIT) { + ici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } + } else { + ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + VmaAllocationCreateInfo allocCreateInfo{}; + allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + VmaAllocationInfo allocInfo{}; + + VkResult res = vmaCreateImage(vulkan->Allocator(), &ici, &allocCreateInfo, &img.image, &img.alloc, &allocInfo); + _dbg_assert_(res == VK_SUCCESS); + + VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; + ivci.format = ici.format; + ivci.image = img.image; + ivci.viewType = numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY; + ivci.subresourceRange.aspectMask = aspects; + ivci.subresourceRange.layerCount = numLayers; + ivci.subresourceRange.levelCount = 1; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView); + vulkan->SetDebugName(img.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); + _dbg_assert_(res == VK_SUCCESS); + + // Separate view for texture sampling all layers together. + if (!color) { + ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } + + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; // layered for consistency, even if single image. + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texAllLayersView); + vulkan->SetDebugName(img.texAllLayersView, VK_OBJECT_TYPE_IMAGE_VIEW, tag); + + // Create 2D views for both layers. + // Useful when multipassing shaders that don't yet exist in a single-pass-stereo version. + for (int i = 0; i < numLayers; i++) { + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; + ivci.subresourceRange.layerCount = 1; + ivci.subresourceRange.baseArrayLayer = i; + res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texLayerViews[i]); + if (vulkan->DebugLayerEnabled()) { + char temp[128]; + snprintf(temp, sizeof(temp), "%s_layer%d", tag, i); + vulkan->SetDebugName(img.texLayerViews[i], VK_OBJECT_TYPE_IMAGE_VIEW, temp); + } + _dbg_assert_(res == VK_SUCCESS); + } + + VkPipelineStageFlags dstStage; + VkAccessFlagBits dstAccessMask; + switch (initialLayout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + default: + Crash(); + return; + } + + TransitionImageLayout2(cmd, img.image, 0, 1, numLayers, aspects, + VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, + 0, dstAccessMask); + img.layout = initialLayout; + img.format = format; + img.sampleCount = sampleCount; + img.tag = tag ? tag : "N/A"; + img.numLayers = numLayers; +} + +static VkAttachmentLoadOp ConvertLoadAction(VKRRenderPassLoadAction action) { + switch (action) { + case VKRRenderPassLoadAction::CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR; + case VKRRenderPassLoadAction::KEEP: return VK_ATTACHMENT_LOAD_OP_LOAD; + case VKRRenderPassLoadAction::DONT_CARE: return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + return VK_ATTACHMENT_LOAD_OP_DONT_CARE; // avoid compiler warning +} + +static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { + switch (action) { + case VKRRenderPassStoreAction::STORE: return VK_ATTACHMENT_STORE_OP_STORE; + case VKRRenderPassStoreAction::DONT_CARE: return VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + return VK_ATTACHMENT_STORE_OP_DONT_CARE; // avoid compiler warning +} + +// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 +// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies + +VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { + bool selfDependency = RenderPassTypeHasInput(rpType); + bool isBackbuffer = rpType == RenderPassType::BACKBUFFER; + bool hasDepth = RenderPassTypeHasDepth(rpType); + bool multiview = RenderPassTypeHasMultiView(rpType); + bool multisample = RenderPassTypeHasMultisample(rpType); + + if (multiview) { + // TODO: Assert that the device has multiview support enabled. + } + + int colorAttachmentIndex = 0; + int depthAttachmentIndex = 1; + + int attachmentCount = 0; + VkAttachmentDescription attachments[4]{}; + attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; + attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.colorLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction); + attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[attachmentCount].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentCount++; + + if (hasDepth) { + attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; + attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.depthLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction); + attachments[attachmentCount].stencilLoadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.stencilLoadAction); + attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); + attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachmentCount++; + } + + if (multisample) { + colorAttachmentIndex = attachmentCount; + attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; + attachments[attachmentCount].samples = sampleCount; + attachments[attachmentCount].loadOp = ConvertLoadAction(key.colorLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction); + attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentCount++; + + if (hasDepth) { + depthAttachmentIndex = attachmentCount; + attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; + attachments[attachmentCount].samples = sampleCount; + attachments[attachmentCount].loadOp = ConvertLoadAction(key.depthLoadAction); + attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction); + attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); + attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); + attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachmentCount++; + } + } + + VkAttachmentReference colorReference{}; + colorReference.attachment = colorAttachmentIndex; + colorReference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthReference{}; + depthReference.attachment = depthAttachmentIndex; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.flags = 0; + if (selfDependency) { + subpass.inputAttachmentCount = 1; + subpass.pInputAttachments = &colorReference; + } else { + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + } + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorReference; + + VkAttachmentReference colorResolveReference; + if (multisample) { + colorResolveReference.attachment = 0; // the non-msaa color buffer. + colorResolveReference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + subpass.pResolveAttachments = &colorResolveReference; + } else { + subpass.pResolveAttachments = nullptr; + } + if (hasDepth) { + subpass.pDepthStencilAttachment = &depthReference; + } + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + // Not sure if this is really necessary. + VkSubpassDependency deps[2]{}; + size_t numDeps = 0; + + VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + rp.attachmentCount = attachmentCount; + rp.pAttachments = attachments; + rp.subpassCount = 1; + rp.pSubpasses = &subpass; + + VkRenderPassMultiviewCreateInfoKHR mv{ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR }; + uint32_t viewMask = 0x3; // Must be outside the 'if (multiview)' scope! + int viewOffset = 0; + if (multiview) { + rp.pNext = &mv; + mv.subpassCount = 1; + mv.pViewMasks = &viewMask; + mv.dependencyCount = 0; + mv.pCorrelationMasks = &viewMask; // same masks + mv.correlationMaskCount = 1; + mv.pViewOffsets = &viewOffset; + } + + if (isBackbuffer) { + deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL; + deps[numDeps].dstSubpass = 0; + deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + deps[numDeps].srcAccessMask = 0; + deps[numDeps].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + numDeps++; + } + + if (selfDependency) { + deps[numDeps].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + deps[numDeps].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + deps[numDeps].srcSubpass = 0; + deps[numDeps].dstSubpass = 0; + numDeps++; + } + + if (numDeps > 0) { + rp.dependencyCount = (u32)numDeps; + rp.pDependencies = deps; + } + + VkRenderPass pass; + VkResult res; + + // We could always use renderpass2, but I think it'll get both paths better tested if we + // only use it with multisample enabled. + // if (vulkan->Extensions().KHR_create_renderpass2) { + if (multisample) { + // It's a bit unfortunate that we can't rely on vkCreateRenderPass2, because here we now have + // to do a bunch of struct conversion, just to not have to repeat the logic from above. + VkAttachmentDescription2KHR attachments2[4]{}; + for (int i = 0; i < attachmentCount; i++) { + attachments2[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; + attachments2[i].format = attachments[i].format; + attachments2[i].samples = attachments[i].samples; + attachments2[i].loadOp = attachments[i].loadOp; + attachments2[i].storeOp = attachments[i].storeOp; + attachments2[i].stencilLoadOp = attachments[i].stencilLoadOp; + attachments2[i].stencilStoreOp = attachments[i].stencilStoreOp; + attachments2[i].initialLayout = attachments[i].initialLayout; + attachments2[i].finalLayout = attachments[i].finalLayout; + } + + VkAttachmentReference2KHR colorReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + colorReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorReference2.attachment = colorReference.attachment; + colorReference2.layout = colorReference.layout; + + VkAttachmentReference2KHR depthReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + depthReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthReference2.attachment = depthReference.attachment; + depthReference2.layout = depthReference.layout; + + VkSubpassDependency2KHR deps2[2]{}; + for (int i = 0; i < numDeps; i++) { + deps2[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR; + deps2[i].dependencyFlags = deps[i].dependencyFlags; + deps2[i].srcAccessMask = deps[i].srcAccessMask; + deps2[i].dstAccessMask = deps[i].dstAccessMask; + deps2[i].srcStageMask = deps[i].srcStageMask; + deps2[i].dstStageMask = deps[i].dstStageMask; + deps2[i].srcSubpass = deps[i].srcSubpass; + deps2[i].dstSubpass = deps[i].dstSubpass; + deps2[i].dependencyFlags = deps[i].dependencyFlags; + deps2[i].viewOffset = 0; + } + + VkAttachmentReference2KHR colorResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + + VkSubpassDescription2KHR subpass2{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR }; + subpass2.colorAttachmentCount = subpass.colorAttachmentCount; + subpass2.flags = subpass.flags; + if (selfDependency) { + subpass2.inputAttachmentCount = subpass.inputAttachmentCount; + subpass2.pInputAttachments = &colorReference2; + } + subpass2.pColorAttachments = &colorReference2; + if (hasDepth) { + subpass2.pDepthStencilAttachment = &depthReference2; + } + subpass2.pipelineBindPoint = subpass.pipelineBindPoint; + subpass2.viewMask = multiview ? viewMask : 0; + if (multisample) { + colorResolveReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorResolveReference2.attachment = colorResolveReference.attachment; // the non-msaa color buffer. + colorResolveReference2.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + subpass2.pResolveAttachments = &colorResolveReference2; + } else { + subpass2.pResolveAttachments = nullptr; + } + + VkAttachmentReference2KHR depthResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; + VkSubpassDescriptionDepthStencilResolveKHR depthStencilResolve{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR }; + if (hasDepth && multisample) { + subpass2.pNext = &depthStencilResolve; + depthResolveReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthResolveReference2.attachment = 1; + depthResolveReference2.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + // TODO: Some games might benefit from the other depth resolve modes when depth texturing. + depthStencilResolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + depthStencilResolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + depthStencilResolve.pDepthStencilResolveAttachment = &depthResolveReference2; + } + + VkRenderPassCreateInfo2KHR rp2{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR }; + rp2.pAttachments = attachments2; + rp2.pDependencies = deps2; + rp2.attachmentCount = rp.attachmentCount; + rp2.dependencyCount = rp.dependencyCount; + rp2.correlatedViewMaskCount = multiview ? 1 : 0; + rp2.pCorrelatedViewMasks = multiview ? &viewMask : nullptr; + rp2.pSubpasses = &subpass2; + rp2.subpassCount = 1; + res = vkCreateRenderPass2KHR(vulkan->GetDevice(), &rp2, nullptr, &pass); + } else { + res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); + } + + _assert_(res == VK_SUCCESS); + _assert_(pass != VK_NULL_HANDLE); + return pass; +} + +VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { + // When we create a render pass, we create all "types" of it immediately, + // practical later when referring to it. Could change to on-demand if it feels motivated + // but I think the render pass objects are cheap. + + // WARNING: We don't include sampleCount in the key, there's only the distinction multisampled or not + // which comes from the rpType. + // So you CAN NOT mix and match different non-one sample counts. + + _dbg_assert_(!((rpType & RenderPassType::MULTISAMPLE) && sampleCount == VK_SAMPLE_COUNT_1_BIT)); + + if (!pass[(int)rpType] || sampleCounts[(int)rpType] != sampleCount) { + if (pass[(int)rpType]) { + vulkan->Delete().QueueDeleteRenderPass(pass[(int)rpType]); + } + pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType, sampleCount); + sampleCounts[(int)rpType] = sampleCount; + } + return pass[(int)rpType]; +} diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.h b/Common/GPU/Vulkan/VulkanFramebuffer.h new file mode 100644 index 0000000000..fc584f4b8c --- /dev/null +++ b/Common/GPU/Vulkan/VulkanFramebuffer.h @@ -0,0 +1,164 @@ +#pragma once + +#include "Common/Common.h" +#include "Common/GPU/Vulkan/VulkanContext.h" + +class VKRRenderPass; + +// Pipelines need to be created for the right type of render pass. +// TODO: Rename to RenderPassFlags? +// When you add more flags, don't forget to update rpTypeDebugNames[]. +enum class RenderPassType { + DEFAULT = 0, + // These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so + // they can be OR-ed together in MergeRPTypes. + HAS_DEPTH = 1, + COLOR_INPUT = 2, // input attachment + MULTIVIEW = 4, + MULTISAMPLE = 8, + + // This is the odd one out, and gets special handling in MergeRPTypes. + // If this flag is set, none of the other flags can be set. + // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible + // so we don't bother with a non-depth version. + BACKBUFFER = 16, + + TYPE_COUNT = BACKBUFFER + 1, +}; +ENUM_CLASS_BITOPS(RenderPassType); + +// Simple independent framebuffer image. +struct VKRImage { + // These four are "immutable". + VkImage image; + + VkImageView rtView; // Used for rendering to, and readbacks of stencil. 2D if single layer, 2D_ARRAY if multiple. Includes both depth and stencil if depth/stencil. + + // This is for texturing all layers at once. If aspect is depth/stencil, does not include stencil. + VkImageView texAllLayersView; + + // If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo. + // If there's only one layer, layerViews[0] only is initialized. + VkImageView texLayerViews[2]{}; + + VmaAllocation alloc; + VkFormat format; + VkSampleCountFlagBits sampleCount; + + // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. + VkImageLayout layout; + + int numLayers; + + // For debugging. + std::string tag; + + void Delete(VulkanContext *vulkan); +}; + +class VKRFramebuffer { +public: + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag); + ~VKRFramebuffer(); + + VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); + + int width = 0; + int height = 0; + int numLayers = 0; + VkSampleCountFlagBits sampleCount; + + VKRImage color{}; // color.image is always there. + VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE. + + // These are only initialized and used if numSamples > 1. + VKRImage msaaColor{}; + VKRImage msaaDepth{}; + + const char *Tag() const { + return tag_.c_str(); + } + + void UpdateTag(const char *newTag); + + bool HasDepth() const { + return depth.image != VK_NULL_HANDLE; + } + + VkImageView GetRTView() { + if (sampleCount == VK_SAMPLE_COUNT_1_BIT) { + return color.rtView; + } else { + return msaaColor.rtView; + } + } + + VulkanContext *Vulkan() const { return vulkan_; } +private: + static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); + + VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{}; + + VulkanContext *vulkan_; + std::string tag_; +}; + +inline bool RenderPassTypeHasDepth(RenderPassType type) { + return (type & RenderPassType::HAS_DEPTH) || type == RenderPassType::BACKBUFFER; +} + +inline bool RenderPassTypeHasInput(RenderPassType type) { + return (type & RenderPassType::COLOR_INPUT) != 0; +} + +inline bool RenderPassTypeHasMultiView(RenderPassType type) { + return (type & RenderPassType::MULTIVIEW) != 0; +} + +inline bool RenderPassTypeHasMultisample(RenderPassType type) { + return (type & RenderPassType::MULTISAMPLE) != 0; +} + +VkSampleCountFlagBits MultiSampleLevelToFlagBits(int count); + +// Must be the same order as Draw::RPAction +enum class VKRRenderPassLoadAction : uint8_t { + KEEP, // default. avoid when possible. + CLEAR, + DONT_CARE, +}; + +enum class VKRRenderPassStoreAction : uint8_t { + STORE, // default. avoid when possible. + DONT_CARE, +}; + +struct RPKey { + // Only render-pass-compatibility-volatile things can be here. + VKRRenderPassLoadAction colorLoadAction; + VKRRenderPassLoadAction depthLoadAction; + VKRRenderPassLoadAction stencilLoadAction; + VKRRenderPassStoreAction colorStoreAction; + VKRRenderPassStoreAction depthStoreAction; + VKRRenderPassStoreAction stencilStoreAction; +}; + +class VKRRenderPass { +public: + VKRRenderPass(const RPKey &key) : key_(key) {} + + VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount); + void Destroy(VulkanContext *vulkan) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { + if (pass[i]) { + vulkan->Delete().QueueDeleteRenderPass(pass[i]); + } + } + } + +private: + // TODO: Might be better off with a hashmap once the render pass type count grows really large.. + VkRenderPass pass[(size_t)RenderPassType::TYPE_COUNT]{}; + VkSampleCountFlagBits sampleCounts[(size_t)RenderPassType::TYPE_COUNT]; + RPKey key_; +}; diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index 72eb339c12..8efcb69834 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -5,9 +5,15 @@ #include "Common/GPU/Vulkan/VulkanAlloc.h" #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/StringUtils.h" using namespace PPSSPP_VK; +VulkanTexture::VulkanTexture(VulkanContext *vulkan, const char *tag) + : vulkan_(vulkan) { + truncate_cpy(tag_, tag); +} + void VulkanTexture::Wipe() { if (view_ != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImageView(view_); @@ -80,14 +86,14 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i VkResult res = vmaCreateImage(vulkan_->Allocator(), &image_create_info, &allocCreateInfo, &image_, &allocation_, &allocInfo); // Apply the tag - vulkan_->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_.c_str()); + vulkan_->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_); // Write a command to transition the image to the requested layout, if it's not already that layout. if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { switch (initialLayout) { case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: case VK_IMAGE_LAYOUT_GENERAL: - TransitionImageLayout2(cmd, image_, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT); @@ -123,6 +129,16 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; } + vulkan_->SetDebugName(view_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_); + + // Additionally, create an array view, but only if it's a 2D texture. + if (view_info.viewType == VK_IMAGE_VIEW_TYPE_2D) { + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &arrayView_); + _assert_(res == VK_SUCCESS); + vulkan_->SetDebugName(arrayView_, VK_OBJECT_TYPE_IMAGE_VIEW, tag_); + } + return true; } @@ -164,7 +180,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo _assert_msg_(firstMipToGenerate < numMips_, "Can't generate levels beyond storage"); // Transition the pre-set levels to GENERAL. - TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, 1, VK_IMAGE_ASPECT_COLOR_BIT, fromCompute ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, fromCompute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -173,7 +189,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo VK_ACCESS_TRANSFER_READ_BIT); // Do the same with the uninitialized levels. - TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate, + TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, @@ -206,7 +222,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo vkCmdBlitImage(cmd, image_, VK_IMAGE_LAYOUT_GENERAL, image_, VK_IMAGE_LAYOUT_GENERAL, 1, &blit, VK_FILTER_LINEAR); - TransitionImageLayout2(cmd, image_, mip, 1, VK_IMAGE_ASPECT_COLOR_BIT, + TransitionImageLayout2(cmd, image_, mip, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); @@ -214,7 +230,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo } void VulkanTexture::EndCreate(VkCommandBuffer cmd, bool vertexTexture, VkPipelineStageFlags prevStage, VkImageLayout layout) { - TransitionImageLayout2(cmd, image_, 0, numMips_, + TransitionImageLayout2(cmd, image_, 0, numMips_, 1, VK_IMAGE_ASPECT_COLOR_BIT, layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, prevStage, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, @@ -237,6 +253,7 @@ VkImageView VulkanTexture::CreateViewForMip(int mip) { view_info.subresourceRange.layerCount = 1; VkImageView view; VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view); + vulkan_->SetDebugName(view, VK_OBJECT_TYPE_IMAGE_VIEW, "mipview"); _assert_(res == VK_SUCCESS); return view; } @@ -245,6 +262,9 @@ void VulkanTexture::Destroy() { if (view_ != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImageView(view_); } + if (arrayView_ != VK_NULL_HANDLE) { + vulkan_->Delete().QueueDeleteImageView(arrayView_); + } if (image_ != VK_NULL_HANDLE) { _dbg_assert_(allocation_ != VK_NULL_HANDLE); vulkan_->Delete().QueueDeleteImageAllocation(image_, allocation_); diff --git a/Common/GPU/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h index 50d7e0c7f5..c088fdca5b 100644 --- a/Common/GPU/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -1,6 +1,5 @@ #pragma once -#include #include "VulkanLoader.h" class VulkanContext; @@ -12,9 +11,7 @@ VK_DEFINE_HANDLE(VmaAllocation); // ALWAYS use an allocator when calling CreateDirect. class VulkanTexture { public: - VulkanTexture(VulkanContext *vulkan) - : vulkan_(vulkan) { - } + VulkanTexture(VulkanContext *vulkan, const char *tag); ~VulkanTexture() { Destroy(); } @@ -37,13 +34,9 @@ public: void Destroy(); - void SetTag(const char *tag) { - tag_ = tag; - } - const std::string &Tag() const { + const char *Tag() const { return tag_; } - void Touch() {} // Used in image copies, etc. VkImage GetImage() const { return image_; } @@ -51,6 +44,9 @@ public: // Used for sampling, generally. VkImageView GetImageView() const { return view_; } + // For use with some shaders, we might want to view it as a single entry array for convenience. + VkImageView GetImageArrayView() const { return arrayView_; } + int32_t GetWidth() const { return width_; } int32_t GetHeight() const { return height_; } int32_t GetNumMips() const { return numMips_; } @@ -62,6 +58,7 @@ private: VulkanContext *vulkan_; VkImage image_ = VK_NULL_HANDLE; VkImageView view_ = VK_NULL_HANDLE; + VkImageView arrayView_ = VK_NULL_HANDLE; VmaAllocation allocation_ = VK_NULL_HANDLE; int16_t width_ = 0; @@ -70,5 +67,5 @@ private: int16_t depth_ = 1; VkFormat format_ = VK_FORMAT_UNDEFINED; - std::string tag_; + char tag_[64]; }; diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index b0c2ab370b..94092b2166 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -223,6 +223,7 @@ PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; } // namespace PPSSPP_VK using namespace PPSSPP_VK; @@ -239,7 +240,6 @@ static VulkanLibraryHandle vulkanLibrary; typedef void *VulkanLibraryHandle; static VulkanLibraryHandle vulkanLibrary; #endif -const char *VulkanResultToString(VkResult res); bool g_vulkanAvailabilityChecked = false; bool g_vulkanMayBeAvailable = false; @@ -274,6 +274,8 @@ static VulkanLibraryHandle VulkanLoadLibrary(const char *logname) { #if PPSSPP_PLATFORM(SWITCH) // Always unavailable, for now. return nullptr; +#elif PPSSPP_PLATFORM(UWP) + return nullptr; #elif PPSSPP_PLATFORM(WINDOWS) return LoadLibrary(L"vulkan-1.dll"); #else @@ -308,9 +310,8 @@ void VulkanSetAvailable(bool available) { } bool VulkanMayBeAvailable() { - - //unsupported in VR at the moment - if (IsVRBuild()) { + // Unsupported in VR at the moment + if (IsVREnabled()) { return false; } @@ -720,8 +721,58 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); } + if (enabledExtensions.KHR_create_renderpass2) { + LOAD_DEVICE_FUNC(device, vkCreateRenderPass2KHR); + } } void VulkanFree() { VulkanFreeLibrary(vulkanLibrary); } + +const char *VulkanResultToString(VkResult res) { + static char temp[128]{}; + switch (res) { + case VK_NOT_READY: return "VK_NOT_READY"; + case VK_TIMEOUT: return "VK_TIMEOUT"; + case VK_EVENT_SET: return "VK_EVENT_SET"; + case VK_EVENT_RESET: return "VK_EVENT_RESET"; + case VK_INCOMPLETE: return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_ERROR_OUT_OF_POOL_MEMORY: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; + case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN (-13)"; + case VK_ERROR_FRAGMENTATION: return "VK_ERROR_FRAGMENTATION"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; + case VK_PIPELINE_COMPILE_REQUIRED: return "VK_PIPELINE_COMPILE_REQUIRED"; + case VK_ERROR_VALIDATION_FAILED_EXT: return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_INVALID_SHADER_NV: return "VK_ERROR_INVALID_SHADER_NV"; + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VK_ERROR_NOT_PERMITTED_KHR: return "VK_ERROR_NOT_PERMITTED_KHR"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VK_THREAD_IDLE_KHR: return "VK_THREAD_IDLE_KHR"; + case VK_THREAD_DONE_KHR: return "VK_THREAD_DONE_KHR"; + case VK_OPERATION_DEFERRED_KHR: return "VK_OPERATION_DEFERRED_KHR"; + case VK_OPERATION_NOT_DEFERRED_KHR: return "VK_OPERATION_NOT_DEFERRED_KHR"; + default: + // This isn't thread safe, but this should be rare, and at worst, we'll get a jumble of two messages. + snprintf(temp, sizeof(temp), "VK_ERROR_???: 0x%08x", (u32)res); + return temp; + } +} diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h index b0c14570da..caaef0d597 100644 --- a/Common/GPU/Vulkan/VulkanLoader.h +++ b/Common/GPU/Vulkan/VulkanLoader.h @@ -224,6 +224,7 @@ extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; } // namespace PPSSPP_VK // For fast extension-enabled checks. @@ -254,3 +255,5 @@ bool VulkanLoad(); void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions); void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions); void VulkanFree(); + +const char *VulkanResultToString(VkResult res); diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp index 8206c80c91..d8184098a5 100644 --- a/Common/GPU/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -153,7 +153,7 @@ void VulkanDescSetPool::Create(VulkanContext *vulkan, const VkDescriptorPoolCrea _assert_msg_(res == VK_SUCCESS, "Could not create VulkanDescSetPool %s", tag_); } -VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout *layouts) { +VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag) { if (descPool_ == VK_NULL_HANDLE || usage_ + n >= info_.maxSets) { // Missing or out of space, need to recreate. VkResult res = Recreate(grow_); @@ -180,9 +180,12 @@ VkDescriptorSet VulkanDescSetPool::Allocate(int n, const VkDescriptorSetLayout * _assert_msg_(result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result); } - if (result == VK_SUCCESS) - return desc; - return VK_NULL_HANDLE; + if (result != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + vulkan_->SetDebugName(desc, VK_OBJECT_TYPE_DESCRIPTOR_SET, tag); + return desc; } void VulkanDescSetPool::Reset() { diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h index 79a71d4ce6..275ca4bb78 100644 --- a/Common/GPU/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -121,6 +122,15 @@ public: return writePtr_ + off; } + template + void PushUBOData(const T &data, VkDescriptorBufferInfo *info) { + uint32_t bindOffset; + void *ptr = PushAligned(sizeof(T), &bindOffset, &info->buffer, vulkan_->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment); + memcpy(ptr, &data, sizeof(T)); + info->offset = bindOffset; + info->range = sizeof(T); + } + size_t GetTotalSize() const; private: @@ -153,7 +163,7 @@ public: void Create(VulkanContext *vulkan, const VkDescriptorPoolCreateInfo &info, const std::vector &sizes); // Allocate a new set, which may resize and empty the current sets. // Use only for the current frame, unless in a cache cleared by clear_. - VkDescriptorSet Allocate(int n, const VkDescriptorSetLayout *layouts); + VkDescriptorSet Allocate(int n, const VkDescriptorSetLayout *layouts, const char *tag); void Reset(); void Destroy(); diff --git a/Common/GPU/Vulkan/VulkanProfiler.cpp b/Common/GPU/Vulkan/VulkanProfiler.cpp index fccea843b8..6e3a959f30 100644 --- a/Common/GPU/Vulkan/VulkanProfiler.cpp +++ b/Common/GPU/Vulkan/VulkanProfiler.cpp @@ -40,7 +40,7 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm // Log it all out. for (auto &scope : scopes_) { if (scope.endQueryId == -1) { - WARN_LOG(G3D, "Unclosed scope: %s", scope.name.c_str()); + WARN_LOG(G3D, "Unclosed scope: %s", scope.name); continue; } uint64_t startTime = results[scope.startQueryId]; @@ -50,7 +50,7 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm double milliseconds = (double)delta * timestampConversionFactor; - INFO_LOG(G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name.c_str(), milliseconds); + INFO_LOG(G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds); } scopes_.clear(); @@ -73,14 +73,11 @@ void VulkanProfiler::Begin(VkCommandBuffer cmdBuf, VkPipelineStageFlagBits stage return; } + ProfilerScope scope; va_list args; va_start(args, fmt); - char temp[512]; - vsnprintf(temp, sizeof(temp), fmt, args); + vsnprintf(scope.name, sizeof(scope.name), fmt, args); va_end(args); - - ProfilerScope scope; - scope.name = temp; scope.startQueryId = numQueries_; scope.endQueryId = -1; scope.level = (int)scopeStack_.size(); diff --git a/Common/GPU/Vulkan/VulkanProfiler.h b/Common/GPU/Vulkan/VulkanProfiler.h index d7b08d6738..e3d21c2021 100644 --- a/Common/GPU/Vulkan/VulkanProfiler.h +++ b/Common/GPU/Vulkan/VulkanProfiler.h @@ -13,7 +13,7 @@ // Put the whole thing in a FrameData to allow for overlap. struct ProfilerScope { - std::string name; + char name[52]; // to make a struct size of 64, just because int startQueryId; int endQueryId; int level; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index b085adcef7..53f5615931 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -3,6 +3,7 @@ #include "Common/GPU/DataFormat.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" #include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/TimeUtil.h" @@ -10,7 +11,7 @@ using namespace PPSSPP_VK; // Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP NativeGLView NativeRenderer NativeSurfaceView PowerSaveModeReceiver InputDeviceState -static void MergeRenderAreaRectInto(VkRect2D *dest, VkRect2D &src) { +static void MergeRenderAreaRectInto(VkRect2D *dest, const VkRect2D &src) { if (dest->offset.x > src.offset.x) { dest->extent.width += (dest->offset.x - src.offset.x); dest->offset.x = src.offset.x; @@ -31,11 +32,13 @@ static void MergeRenderAreaRectInto(VkRect2D *dest, VkRect2D &src) { RenderPassType MergeRPTypes(RenderPassType a, RenderPassType b) { // Either both are backbuffer type, or neither are. // These can't merge with other renderpasses - if (a == RP_TYPE_BACKBUFFER || b == RP_TYPE_BACKBUFFER) { + if (a == RenderPassType::BACKBUFFER || b == RenderPassType::BACKBUFFER) { _dbg_assert_(a == b); return a; } + _dbg_assert_((a & RenderPassType::MULTIVIEW) == (b & RenderPassType::MULTIVIEW)); + // The rest we can just OR together to get the maximum feature set. return (RenderPassType)((u32)a | (u32)b); } @@ -165,7 +168,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) { color_image_view.subresourceRange.baseMipLevel = 0; color_image_view.subresourceRange.levelCount = 1; color_image_view.subresourceRange.baseArrayLayer = 0; - color_image_view.subresourceRange.layerCount = 1; + color_image_view.subresourceRange.layerCount = 1; // TODO: Investigate hw-assisted stereo. color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; color_image_view.flags = 0; color_image_view.image = sc_buffer.image; @@ -175,6 +178,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) { // Also, turns out it's illegal to transition un-acquired images, thanks Hans-Kristian. See #11417. res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, nullptr, &sc_buffer.view); + vulkan_->SetDebugName(sc_buffer.view, VK_OBJECT_TYPE_IMAGE_VIEW, "swapchain_view"); swapchainImages_.push_back(sc_buffer); _dbg_assert_(res == VK_SUCCESS); } @@ -194,7 +198,7 @@ bool VulkanQueueRunner::InitBackbufferFramebuffers(int width, int height) { VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view }; VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RP_TYPE_BACKBUFFER); + fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT); fb_info.attachmentCount = 2; fb_info.pAttachments = attachments; fb_info.width = width; @@ -248,7 +252,7 @@ bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) { vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth"); - TransitionImageLayout2(cmd, depth_.image, 0, 1, + TransitionImageLayout2(cmd, depth_.image, 0, 1, 1, aspectMask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, @@ -273,6 +277,7 @@ bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) { VkDevice device = vulkan_->GetDevice(); res = vkCreateImageView(device, &depth_view_info, NULL, &depth_.view); + vulkan_->SetDebugName(depth_.view, VK_OBJECT_TYPE_IMAGE_VIEW, "depth_stencil_backbuffer"); _dbg_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) return false; @@ -304,133 +309,6 @@ void VulkanQueueRunner::DestroyBackBuffers() { INFO_LOG(G3D, "Backbuffers destroyed"); } -static VkAttachmentLoadOp ConvertLoadAction(VKRRenderPassLoadAction action) { - switch (action) { - case VKRRenderPassLoadAction::CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR; - case VKRRenderPassLoadAction::KEEP: return VK_ATTACHMENT_LOAD_OP_LOAD; - case VKRRenderPassLoadAction::DONT_CARE: return VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - return VK_ATTACHMENT_LOAD_OP_DONT_CARE; // avoid compiler warning -} - -static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) { - switch (action) { - case VKRRenderPassStoreAction::STORE: return VK_ATTACHMENT_STORE_OP_STORE; - case VKRRenderPassStoreAction::DONT_CARE: return VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - return VK_ATTACHMENT_STORE_OP_DONT_CARE; // avoid compiler warning -} - -// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 -// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies - -VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) { - bool selfDependency = rpType == RP_TYPE_COLOR_INPUT || rpType == RP_TYPE_COLOR_DEPTH_INPUT; - bool isBackbuffer = rpType == RP_TYPE_BACKBUFFER; - bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT; - - VkAttachmentDescription attachments[2] = {}; - attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = ConvertLoadAction(key.colorLoadAction); - attachments[0].storeOp = ConvertStoreAction(key.colorStoreAction); - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].flags = 0; - - if (hasDepth) { - attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat; - attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction); - attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction); - attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction); - attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction); - attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].flags = 0; - } - - VkAttachmentReference color_reference{}; - color_reference.attachment = 0; - color_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference depth_reference{}; - depth_reference.attachment = 1; - depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass{}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - if (selfDependency) { - subpass.inputAttachmentCount = 1; - subpass.pInputAttachments = &color_reference; - } else { - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = nullptr; - } - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_reference; - subpass.pResolveAttachments = nullptr; - if (hasDepth) { - subpass.pDepthStencilAttachment = &depth_reference; - } - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = nullptr; - - // Not sure if this is really necessary. - VkSubpassDependency deps[2]{}; - size_t numDeps = 0; - - VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - rp.attachmentCount = hasDepth ? 2 : 1; - rp.pAttachments = attachments; - rp.subpassCount = 1; - rp.pSubpasses = &subpass; - - if (isBackbuffer) { - deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL; - deps[numDeps].dstSubpass = 0; - deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].srcAccessMask = 0; - deps[numDeps].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - numDeps++; - } - - if (selfDependency) { - deps[numDeps].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - deps[numDeps].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - deps[numDeps].srcSubpass = 0; - deps[numDeps].dstSubpass = 0; - numDeps++; - } - - if (numDeps > 0) { - rp.dependencyCount = (u32)numDeps; - rp.pDependencies = deps; - } - - VkRenderPass pass; - VkResult res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); - _assert_(res == VK_SUCCESS); - _assert_(pass != VK_NULL_HANDLE); - return pass; -} - -VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType) { - // When we create a render pass, we create all "types" of it immediately, - // practical later when referring to it. Could change to on-demand if it feels motivated - // but I think the render pass objects are cheap. - if (!pass[(int)rpType]) { - pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType); - } - return pass[(int)rpType]; -} // Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 // Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies @@ -456,6 +334,7 @@ void VulkanQueueRunner::SelfDependencyBarrier(VKRImage &img, VkImageAspectFlags img.image, 0, 1, + img.numLayers, aspect, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, @@ -546,7 +425,7 @@ void VulkanQueueRunner::PreprocessSteps(std::vector &steps) { } } -void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared) { +void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared, bool keepSteps) { QueueProfileContext *profile = frameData.profilingEnabled_ ? &frameData.profile : nullptr; if (profile) @@ -624,12 +503,13 @@ void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frame // Deleting all in one go should be easier on the instruction cache than deleting // them as we go - and easier to debug because we can look backwards in the frame. - for (auto step : steps) { - delete step; + if (!keepSteps) { + for (auto step : steps) { + delete step; + } + steps.clear(); } - steps.clear(); - if (profile) profile->cpuEndTime = time_now_d(); } @@ -873,6 +753,26 @@ const char *AspectToString(VkImageAspectFlags aspect) { } } +static const char *rpTypeDebugNames[] = { + "RENDER", + "RENDER_DEPTH", + "RENDER_INPUT", + "RENDER_DEPTH_INPUT", + "MV_RENDER", + "MV_RENDER_DEPTH", + "MV_RENDER_INPUT", + "MV_RENDER_DEPTH_INPUT", + "MS_RENDER", + "MS_RENDER_DEPTH", + "MS_RENDER_INPUT", + "MS_RENDER_DEPTH_INPUT", + "MS_MV_RENDER", + "MS_MV_RENDER_DEPTH", + "MS_MV_RENDER_INPUT", + "MS_MV_RENDER_DEPTH_INPUT", + "BACKBUF", +}; + std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { char buffer[256]; switch (step.stepType) { @@ -882,15 +782,7 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight(); int actual_w = step.render.renderArea.extent.width; int actual_h = step.render.renderArea.extent.height; - const char *renderCmd; - switch (step.render.renderPassType) { - case RP_TYPE_BACKBUFFER: renderCmd = "BACKBUF"; break; - case RP_TYPE_COLOR: renderCmd = "RENDER"; break; - case RP_TYPE_COLOR_DEPTH: renderCmd = "RENDER_DEPTH"; break; - case RP_TYPE_COLOR_INPUT: renderCmd = "RENDER_INPUT"; break; - case RP_TYPE_COLOR_DEPTH_INPUT: renderCmd = "RENDER_DEPTH_INPUT"; break; - default: renderCmd = "N/A"; - } + const char *renderCmd = rpTypeDebugNames[(size_t)step.render.renderPassType]; snprintf(buffer, sizeof(buffer), "%s %s %s (draws: %d, %dx%d/%dx%d)", renderCmd, step.tag, step.render.framebuffer ? step.render.framebuffer->Tag() : "", step.render.numDraws, actual_w, actual_h, w, h); break; } @@ -1113,6 +1005,12 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { case VKRRenderCommand::PUSH_CONSTANTS: INFO_LOG(G3D, " PushConstants(%d)", cmd.push.size); break; + case VKRRenderCommand::DEBUG_ANNOTATION: + INFO_LOG(G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation); + break; + case VKRRenderCommand::BIND_DESCRIPTOR_SET: + INFO_LOG(G3D, " BindDescSet(%d)", cmd.bindDescSet.setNumber); + break; case VKRRenderCommand::NUM_RENDER_COMMANDS: break; @@ -1140,7 +1038,7 @@ void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) { INFO_LOG(G3D, "%s", StepToString(step).c_str()); } -void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout, VulkanBarrier *recordBarrier) { +void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout, int numLayers, VulkanBarrier *recordBarrier) { if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { VkPipelineStageFlags srcStageMask = 0; VkAccessFlags srcAccessMask = 0; @@ -1173,7 +1071,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout break; } recordBarrier->TransitionImage( - colorImage, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + colorImage, 0, 1, numLayers, VK_IMAGE_ASPECT_COLOR_BIT, colorLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, srcAccessMask, @@ -1209,7 +1107,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout break; } recordBarrier->TransitionImage( - depthStencilImage, 0, 1, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + depthStencilImage, 0, 1, numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, depthStencilLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, srcAccessMask, @@ -1219,7 +1117,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout } } -void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout) { +void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, int numLayers, VkImageLayout depthStencilLayout) { VkPipelineStageFlags srcStageMask = 0; VkPipelineStageFlags dstStageMask = 0; @@ -1261,7 +1159,7 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier[0].subresourceRange.baseMipLevel = 0; barrier[0].subresourceRange.levelCount = 1; - barrier[0].subresourceRange.layerCount = 1; + barrier[0].subresourceRange.layerCount = numLayers; barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrierCount++; @@ -1300,7 +1198,7 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou barrier[barrierCount].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; barrier[barrierCount].subresourceRange.baseMipLevel = 0; barrier[barrierCount].subresourceRange.levelCount = 1; - barrier[barrierCount].subresourceRange.layerCount = 1; + barrier[barrierCount].subresourceRange.layerCount = numLayers; barrier[barrierCount].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier[barrierCount].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrierCount++; @@ -1318,6 +1216,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c iter.fb->color.image, 0, 1, + iter.fb->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, iter.fb->color.layout, iter.targetLayout @@ -1328,6 +1227,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c iter.fb->depth.image, 0, 1, + iter.fb->numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, iter.fb->depth.layout, iter.targetLayout @@ -1357,6 +1257,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c step.render.framebuffer->color.image, 0, 1, + step.render.framebuffer->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -1371,6 +1272,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c step.render.framebuffer->depth.image, 0, 1, + step.render.framebuffer->numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, @@ -1404,13 +1306,16 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkPipeline lastPipeline = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + bool pipelineOK = false; + int lastStencilWriteMask = -1; int lastStencilCompareMask = -1; int lastStencilReference = -1; const RenderPassType rpType = step.render.renderPassType; - for (const auto &c : commands) { + for (size_t i = 0; i < commands.size(); i++) { + const VkRenderData &c = commands[i]; switch (c.cmd) { case VKRRenderCommand::REMOVED: break; @@ -1419,26 +1324,39 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c { VKRGraphicsPipeline *graphicsPipeline = c.graphics_pipeline.pipeline; if (graphicsPipeline != lastGraphicsPipeline) { - if (!graphicsPipeline->pipeline[rpType]) { + VkSampleCountFlagBits fbSampleCount = fb ? fb->sampleCount : VK_SAMPLE_COUNT_1_BIT; + + if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) { + // should have been invalidated. + _assert_msg_(graphicsPipeline->SampleCount() == VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM, + "expected %d sample count, got %d", fbSampleCount, graphicsPipeline->SampleCount()); + } + + if (!graphicsPipeline->pipeline[(size_t)rpType]) { // NOTE: If render steps got merged, it can happen that, as they ended during recording, // they didn't know their final render pass type so they created the wrong pipelines in EndCurRenderStep(). // Unfortunately I don't know if we can fix it in any more sensible place than here. // Maybe a middle pass. But let's try to just block and compile here for now, this doesn't // happen all that much. - graphicsPipeline->pipeline[rpType] = Promise::CreateEmpty(); - graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType), rpType); + graphicsPipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); + graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, fbSampleCount), rpType, fbSampleCount); } - VkPipeline pipeline = graphicsPipeline->pipeline[rpType]->BlockUntilReady(); + VkPipeline pipeline = graphicsPipeline->pipeline[(size_t)rpType]->BlockUntilReady(); + if (pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); pipelineLayout = c.pipeline.pipelineLayout; lastGraphicsPipeline = graphicsPipeline; - // Reset dynamic state so it gets refreshed with the new pipeline. - lastStencilWriteMask = -1; - lastStencilCompareMask = -1; - lastStencilReference = -1; + pipelineOK = true; + } else { + pipelineOK = false; } + + // Reset dynamic state so it gets refreshed with the new pipeline. + lastStencilWriteMask = -1; + lastStencilCompareMask = -1; + lastStencilReference = -1; } break; } @@ -1503,14 +1421,22 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c case VKRRenderCommand::SELF_DEPENDENCY_BARRIER: { _assert_(step.render.pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT); + _assert_(fb); VulkanBarrier barrier; - SelfDependencyBarrier(step.render.framebuffer->color, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + if (fb->sampleCount != VK_SAMPLE_COUNT_1_BIT) { + // Rendering is happening to the multisample buffer, not the color buffer. + SelfDependencyBarrier(fb->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + } else { + SelfDependencyBarrier(fb->color, VK_IMAGE_ASPECT_COLOR_BIT, &barrier); + } barrier.Flush(cmd); break; } case VKRRenderCommand::PUSH_CONSTANTS: - vkCmdPushConstants(cmd, pipelineLayout, c.push.stages, c.push.offset, c.push.size, c.push.data); + if (pipelineOK) { + vkCmdPushConstants(cmd, pipelineLayout, c.push.stages, c.push.offset, c.push.size, c.push.data); + } break; case VKRRenderCommand::STENCIL: @@ -1529,21 +1455,23 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c break; case VKRRenderCommand::DRAW_INDEXED: - { - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); - vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); - VkDeviceSize voffset = c.drawIndexed.voffset; - vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); - vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0); + if (pipelineOK) { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); + vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); + VkDeviceSize voffset = c.drawIndexed.voffset; + vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); + vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0); + } break; - } case VKRRenderCommand::DRAW: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); - if (c.draw.vbuffer) { - vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); + if (pipelineOK) { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); + if (c.draw.vbuffer) { + vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); + } + vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0); } - vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0); break; case VKRRenderCommand::CLEAR: @@ -1552,7 +1480,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c int numAttachments = 0; VkClearRect rc{}; rc.baseArrayLayer = 0; - rc.layerCount = 1; + rc.layerCount = 1; // In multiview mode, 1 means to replicate to all the active layers. rc.rect.extent.width = (uint32_t)curWidth; rc.rect.extent.height = (uint32_t)curHeight; VkClearAttachment attachments[2]{}; @@ -1588,15 +1516,20 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } break; + case VKRRenderCommand::BIND_DESCRIPTOR_SET: + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.bindDescSet.pipelineLayout, c.bindDescSet.setNumber, 1, &c.bindDescSet.set, 0, nullptr); + break; + default: ERROR_LOG(G3D, "Unimpl queue command"); + break; } } vkCmdEndRenderPass(cmd); if (fb) { // If the desired final layout aren't the optimal layout for rendering, transition. - TransitionFromOptimal(cmd, fb->color.image, step.render.finalColorLayout, fb->depth.image, step.render.finalDepthStencilLayout); + TransitionFromOptimal(cmd, fb->color.image, step.render.finalColorLayout, fb->depth.image, fb->numLayers, step.render.finalDepthStencilLayout); fb->color.layout = step.render.finalColorLayout; fb->depth.layout = step.render.finalDepthStencilLayout; @@ -1606,13 +1539,15 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step, VkCommandBuffer cmd) { VKRRenderPass *renderPass; int numClearVals = 0; - VkClearValue clearVal[2]{}; + VkClearValue clearVal[4]{}; VkFramebuffer framebuf; int w; int h; bool hasDepth = RenderPassTypeHasDepth(step.render.renderPassType); + VkSampleCountFlagBits sampleCount; + if (step.render.framebuffer) { _dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED); _dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED); @@ -1625,6 +1560,8 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR VKRFramebuffer *fb = step.render.framebuffer; framebuf = fb->Get(renderPass, step.render.renderPassType); + sampleCount = fb->sampleCount; + _dbg_assert_(framebuf != VK_NULL_HANDLE); w = fb->width; h = fb->height; @@ -1636,7 +1573,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR step.render.colorLoad == VKRRenderPassLoadAction::CLEAR && vulkan_->GetPhysicalDeviceProperties().properties.driverVersion == 0xaa9c4b29; if (maliBugWorkaround) { - recordBarrier_.TransitionImage(step.render.framebuffer->color.image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + recordBarrier_.TransitionImage(fb->color.image, 0, 1, fb->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, fb->color.layout, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, @@ -1644,20 +1581,27 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR fb->color.layout = VK_IMAGE_LAYOUT_GENERAL; } - TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout, &recordBarrier_); + TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout, fb->numLayers, &recordBarrier_); // The transition from the optimal format happens after EndRenderPass, now that we don't // do it as part of the renderpass itself anymore. + if (sampleCount != VK_SAMPLE_COUNT_1_BIT) { + // We don't initialize values for these. + numClearVals = hasDepth ? 2 : 1; // Skip the resolve buffers, don't need to clear those. + } if (step.render.colorLoad == VKRRenderPassLoadAction::CLEAR) { - Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor); - numClearVals = 1; + Uint8x4ToFloat4(clearVal[numClearVals].color.float32, step.render.clearColor); } - if (hasDepth && (step.render.depthLoad == VKRRenderPassLoadAction::CLEAR || step.render.stencilLoad == VKRRenderPassLoadAction::CLEAR)) { - clearVal[1].depthStencil.depth = step.render.clearDepth; - clearVal[1].depthStencil.stencil = step.render.clearStencil; - numClearVals = 2; + numClearVals++; + if (hasDepth) { + if (step.render.depthLoad == VKRRenderPassLoadAction::CLEAR || step.render.stencilLoad == VKRRenderPassLoadAction::CLEAR) { + clearVal[numClearVals].depthStencil.depth = step.render.clearDepth; + clearVal[numClearVals].depthStencil.stencil = step.render.clearStencil; + } + numClearVals++; } + _dbg_assert_(numClearVals != 3); } else { RPKey key{ VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, @@ -1665,7 +1609,11 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR }; renderPass = GetRenderPass(key); - framebuf = backbuffer_; + if (IsVREnabled()) { + framebuf = (VkFramebuffer)BindVRFramebuffer(); + } else { + framebuf = backbuffer_; + } // Raw, rotated backbuffer size. w = vulkan_->GetBackbufferWidth(); @@ -1675,10 +1623,11 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR numClearVals = hasDepth ? 2 : 1; // We might do depth-less backbuffer in the future, though doubtful of the value. clearVal[1].depthStencil.depth = 0.0f; clearVal[1].depthStencil.stencil = 0; + sampleCount = VK_SAMPLE_COUNT_1_BIT; } VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - rp_begin.renderPass = renderPass->Get(vulkan_, step.render.renderPassType); + rp_begin.renderPass = renderPass->Get(vulkan_, step.render.renderPassType, sampleCount); rp_begin.framebuffer = framebuf; VkRect2D rc = step.render.renderArea; @@ -1710,54 +1659,79 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { VKRFramebuffer *src = step.copy.src; VKRFramebuffer *dst = step.copy.dst; - VkImageCopy copy{}; - copy.srcOffset.x = step.copy.srcRect.offset.x; - copy.srcOffset.y = step.copy.srcRect.offset.y; - copy.srcOffset.z = 0; - copy.srcSubresource.mipLevel = 0; - copy.srcSubresource.layerCount = 1; - copy.dstOffset.x = step.copy.dstPos.x; - copy.dstOffset.y = step.copy.dstPos.y; - copy.dstOffset.z = 0; - copy.dstSubresource.mipLevel = 0; - copy.dstSubresource.layerCount = 1; - copy.extent.width = step.copy.srcRect.extent.width; - copy.extent.height = step.copy.srcRect.extent.height; - copy.extent.depth = 1; + int layerCount = std::min(step.copy.src->numLayers, step.copy.dst->numLayers); + _dbg_assert_(step.copy.src->numLayers >= step.copy.dst->numLayers); + + // TODO: If dst covers exactly the whole destination, we can set up a UNDEFINED->TRANSFER_DST_OPTIMAL transition, + // which can potentially be more efficient. // First source barriers. if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - if (src->color.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } - if (dst->color.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } + SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); } // We can't copy only depth or only stencil unfortunately - or can we?. if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { _dbg_assert_(src->depth.image != VK_NULL_HANDLE); - if (src->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - } + SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); if (dst->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); _dbg_assert_(dst->depth.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } else { - // Kingdom Hearts: Subsequent copies to the same depth buffer without any other use. + // Kingdom Hearts: Subsequent copies twice to the same depth buffer without any other use. // Not super sure how that happens, but we need a barrier to pass sync validation. SetupTransferDstWriteAfterWrite(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); } } + recordBarrier_.Flush(cmd); + + bool multisampled = src->sampleCount != VK_SAMPLE_COUNT_1_BIT && dst->sampleCount != VK_SAMPLE_COUNT_1_BIT; + if (multisampled) { + // If both the targets are multisampled, copy the msaa targets too. + // For that, we need to transition them from their normally permanent VK_*_ATTACHMENT_OPTIMAL layouts, and then back. + if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + SetupTransitionToTransferSrc(src->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + SetupTransitionToTransferDst(dst->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + } + if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + // Kingdom Hearts: Subsequent copies to the same depth buffer without any other use. + // Not super sure how that happens, but we need a barrier to pass sync validation. + SetupTransitionToTransferSrc(src->msaaDepth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + SetupTransitionToTransferDst(dst->msaaDepth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + recordBarrier_.Flush(cmd); + } + } recordBarrier_.Flush(cmd); + VkImageCopy copy{}; + copy.srcOffset.x = step.copy.srcRect.offset.x; + copy.srcOffset.y = step.copy.srcRect.offset.y; + copy.srcOffset.z = 0; + copy.srcSubresource.mipLevel = 0; + copy.srcSubresource.layerCount = layerCount; + copy.dstOffset.x = step.copy.dstPos.x; + copy.dstOffset.y = step.copy.dstPos.y; + copy.dstOffset.z = 0; + copy.dstSubresource.mipLevel = 0; + copy.dstSubresource.layerCount = layerCount; + copy.extent.width = step.copy.srcRect.extent.width; + copy.extent.height = step.copy.srcRect.extent.height; + copy.extent.depth = 1; + if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; vkCmdCopyImage(cmd, src->color.image, src->color.layout, dst->color.image, dst->color.layout, 1, ©); + + if (multisampled) { + vkCmdCopyImage(cmd, src->msaaColor.image, src->msaaColor.layout, dst->msaaColor.image, dst->msaaColor.layout, 1, ©); + } } if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { _dbg_assert_(src->depth.image != VK_NULL_HANDLE); @@ -1765,6 +1739,75 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { copy.srcSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); copy.dstSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); vkCmdCopyImage(cmd, src->depth.image, src->depth.layout, dst->depth.image, dst->depth.layout, 1, ©); + + if (multisampled) { + vkCmdCopyImage(cmd, src->msaaDepth.image, src->msaaDepth.layout, dst->msaaDepth.image, dst->msaaDepth.layout, 1, ©); + } + } + + if (multisampled) { + // Transition the MSAA surfaces back to optimal. + if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + recordBarrier_.TransitionImage( + src->msaaColor.image, + 0, + 1, + src->msaaColor.numLayers, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + ); + recordBarrier_.TransitionImage( + dst->msaaColor.image, + 0, + 1, + dst->msaaColor.numLayers, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + ); + src->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + dst->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + recordBarrier_.TransitionImage( + src->msaaDepth.image, + 0, + 1, + src->msaaDepth.numLayers, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT + ); + recordBarrier_.TransitionImage( + dst->msaaDepth.image, + 0, + 1, + dst->msaaDepth.numLayers, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT + ); + src->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + dst->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + recordBarrier_.Flush(cmd); } } @@ -1772,9 +1815,29 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { // The barrier code doesn't handle this case. We'd need to transition to GENERAL to do an intra-image copy. _dbg_assert_(step.blit.src != step.blit.dst); + int layerCount = std::min(step.blit.src->numLayers, step.blit.dst->numLayers); + _dbg_assert_(step.blit.src->numLayers >= step.blit.dst->numLayers); + VKRFramebuffer *src = step.blit.src; VKRFramebuffer *dst = step.blit.dst; + // First source barriers. + if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { + SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + } + + // We can't copy only depth or only stencil unfortunately. + if (step.blit.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + _dbg_assert_(src->depth.image != VK_NULL_HANDLE); + _dbg_assert_(dst->depth.image != VK_NULL_HANDLE); + + SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + } + + recordBarrier_.Flush(cmd); + // If any validation needs to be performed here, it should probably have been done // already when the blit was queued. So don't validate here. VkImageBlit blit{}; @@ -1785,7 +1848,7 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { blit.srcOffsets[1].y = step.blit.srcRect.offset.y + step.blit.srcRect.extent.height; blit.srcOffsets[1].z = 1; blit.srcSubresource.mipLevel = 0; - blit.srcSubresource.layerCount = 1; + blit.srcSubresource.layerCount = layerCount; blit.dstOffsets[0].x = step.blit.dstRect.offset.x; blit.dstOffsets[0].y = step.blit.dstRect.offset.y; blit.dstOffsets[0].z = 0; @@ -1793,38 +1856,7 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { blit.dstOffsets[1].y = step.blit.dstRect.offset.y + step.blit.dstRect.extent.height; blit.dstOffsets[1].z = 1; blit.dstSubresource.mipLevel = 0; - blit.dstSubresource.layerCount = 1; - - VkPipelineStageFlags srcStage = 0; - VkPipelineStageFlags dstStage = 0; - - int srcCount = 0; - int dstCount = 0; - - // First source barriers. - if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - if (src->color.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } - if (dst->color.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - } - } - - // We can't copy only depth or only stencil unfortunately. - if (step.blit.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - _dbg_assert_(src->depth.image != VK_NULL_HANDLE); - _dbg_assert_(dst->depth.image != VK_NULL_HANDLE); - - if (src->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - } - if (dst->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - } - } - - recordBarrier_.Flush(cmd); + blit.dstSubresource.layerCount = layerCount; if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1850,6 +1882,9 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { } void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrier *recordBarrier) { + if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { + return; + } VkImageAspectFlags imageAspect = aspect; VkAccessFlags srcAccessMask = 0; VkPipelineStageFlags srcStageMask = 0; @@ -1886,6 +1921,7 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspec img.image, 0, 1, + img.numLayers, imageAspect, img.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -1898,6 +1934,9 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspec } void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrier *recordBarrier) { + if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + return; + } VkImageAspectFlags imageAspect = aspect; VkAccessFlags srcAccessMask = 0; VkPipelineStageFlags srcStageMask = 0; @@ -1934,6 +1973,7 @@ void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageAspec img.image, 0, 1, + img.numLayers, aspect, img.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -1963,6 +2003,7 @@ void VulkanQueueRunner::SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAs img.image, 0, 1, + img.numLayers, aspect, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -1991,7 +2032,8 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd if (step.readback.src == nullptr) { // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. - TransitionImageLayout2(cmd, backbufferImage_, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + // Regarding layers, backbuffer currently only has one layer. + TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT); @@ -2025,7 +2067,8 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd if (step.readback.src == nullptr) { // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. - TransitionImageLayout2(cmd, backbufferImage_, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, + // Regarding layers, backbuffer currently only has one layer. + TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_TRANSFER_READ_BIT, 0); @@ -2038,6 +2081,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe VKRImage srcImage{}; srcImage.image = step.readback_image.image; srcImage.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcImage.numLayers = 1; SetupTransitionToTransferSrc(srcImage, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); recordBarrier_.Flush(cmd); @@ -2056,7 +2100,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuffer_, 1, ®ion); // Now transfer it back to a texture. - TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, + TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, 1, // I don't think we have any multilayer cases for regular textures. Above in PerformReadback, though.. VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index 396a37edae..0d5f5053ae 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -9,6 +9,7 @@ #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/GPU/Vulkan/VulkanBarrier.h" #include "Common/GPU/Vulkan/VulkanFrameData.h" +#include "Common/GPU/Vulkan/VulkanFramebuffer.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Data/Collections/TinySet.h" #include "Common/GPU/DataFormat.h" @@ -39,42 +40,21 @@ enum class VKRRenderCommand : uint8_t { PUSH_CONSTANTS, SELF_DEPENDENCY_BARRIER, DEBUG_ANNOTATION, + BIND_DESCRIPTOR_SET, NUM_RENDER_COMMANDS, }; -enum class PipelineFlags { +enum class PipelineFlags : u8 { NONE = 0, USES_BLEND_CONSTANT = (1 << 1), USES_DEPTH_STENCIL = (1 << 2), // Reads or writes the depth or stencil buffers. USES_INPUT_ATTACHMENT = (1 << 3), USES_GEOMETRY_SHADER = (1 << 4), + USES_MULTIVIEW = (1 << 5), // Inherited from the render pass it was created with. + USES_DISCARD = (1 << 6), }; ENUM_CLASS_BITOPS(PipelineFlags); -// Pipelines need to be created for the right type of render pass. -enum RenderPassType { - // These four are organized so that bit 0 is DEPTH and bit 1 is INPUT, so - // they can be OR-ed together in MergeRPTypes. - RP_TYPE_COLOR, - RP_TYPE_COLOR_DEPTH, - RP_TYPE_COLOR_INPUT, - RP_TYPE_COLOR_DEPTH_INPUT, - - // This is the odd one out, and gets special handling in MergeRPTypes. - RP_TYPE_BACKBUFFER, // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible. - - // Later will add pure-color render passes. - RP_TYPE_COUNT, -}; - -inline bool RenderPassTypeHasDepth(RenderPassType type) { - return type == RP_TYPE_BACKBUFFER || type == RP_TYPE_COLOR_DEPTH || type == RP_TYPE_COLOR_DEPTH_INPUT; -} - -inline bool RenderPassTypeHasInput(RenderPassType type) { - return type == RP_TYPE_COLOR_INPUT || type == RP_TYPE_COLOR_DEPTH_INPUT; -} - struct VkRenderData { VKRRenderCommand cmd; union { @@ -103,7 +83,7 @@ struct VkRenderData { VkDescriptorSet ds; int numUboOffsets; uint32_t uboOffsets[3]; - VkBuffer vbuffer; // might need to increase at some point + VkBuffer vbuffer; VkBuffer ibuffer; uint32_t voffset; uint32_t ioffset; @@ -140,6 +120,11 @@ struct VkRenderData { struct { const char *annotation; } debugAnnotation; + struct { + int setNumber; + VkDescriptorSet set; + VkPipelineLayout pipelineLayout; + } bindDescSet; }; }; @@ -152,18 +137,6 @@ enum class VKRStepType : uint8_t { READBACK_IMAGE, }; -// Must be the same order as Draw::RPAction -enum class VKRRenderPassLoadAction : uint8_t { - KEEP, // default. avoid when possible. - CLEAR, - DONT_CARE, -}; - -enum class VKRRenderPassStoreAction : uint8_t { - STORE, // default. avoid when possible. - DONT_CARE, -}; - struct TransitionRequest { VKRFramebuffer *fb; VkImageAspectFlags aspect; // COLOR or DEPTH @@ -236,34 +209,6 @@ struct VKRStep { }; }; -struct RPKey { - // Only render-pass-compatibility-volatile things can be here. - VKRRenderPassLoadAction colorLoadAction; - VKRRenderPassLoadAction depthLoadAction; - VKRRenderPassLoadAction stencilLoadAction; - VKRRenderPassStoreAction colorStoreAction; - VKRRenderPassStoreAction depthStoreAction; - VKRRenderPassStoreAction stencilStoreAction; -}; - -class VKRRenderPass { -public: - VKRRenderPass(const RPKey &key) : key_(key) {} - - VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType); - void Destroy(VulkanContext *vulkan) { - for (int i = 0; i < RP_TYPE_COUNT; i++) { - if (pass[i]) { - vulkan->Delete().QueueDeleteRenderPass(pass[i]); - } - } - } - -private: - VkRenderPass pass[RP_TYPE_COUNT]{}; - RPKey key_; -}; - // These are enqueued from the main thread, // and the render thread pops them off struct VKRRenderThreadTask { @@ -282,7 +227,7 @@ public: } void PreprocessSteps(std::vector &steps); - void RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared); + void RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared, bool keepSteps = false); void LogSteps(const std::vector &steps, bool verbose); std::string StepToString(const VKRStep &step) const; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index da43a85d7e..6eb24de9ef 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -12,6 +12,7 @@ #include "Common/GPU/Vulkan/VulkanRenderManager.h" #include "Common/Thread/ThreadUtil.h" +#include "Common/VR/PPSSPPVR.h" #if 0 // def _DEBUG #define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__) @@ -26,7 +27,16 @@ using namespace PPSSPP_VK; // renderPass is an example of the "compatibility class" or RenderPassType type. -bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType) { +bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount) { + bool multisample = RenderPassTypeHasMultisample(rpType); + if (multisample) { + if (sampleCount_ != VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM) { + _assert_(sampleCount == sampleCount_); + } else { + sampleCount_ = sampleCount; + } + } + // Fill in the last part of the desc since now it's time to block. VkShaderModule vs = desc->vertexShader->BlockUntilReady(); VkShaderModule fs = desc->fragmentShader->BlockUntilReady(); @@ -38,6 +48,12 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR return false; } + if (!compatibleRenderPass) { + ERROR_LOG(G3D, "Failed creating graphics pipeline - compatible render pass was null"); + // We're kinda screwed here? + return false; + } + uint32_t stageCount = 2; VkPipelineShaderStageCreateInfo ss[3]{}; ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -68,13 +84,24 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR pipe.pDepthStencilState = &desc->dss; pipe.pRasterizationState = &desc->rs; + VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + ms.rasterizationSamples = multisample ? sampleCount : VK_SAMPLE_COUNT_1_BIT; + if (multisample && (flags_ & PipelineFlags::USES_DISCARD)) { + // Extreme quality + ms.sampleShadingEnable = true; + ms.minSampleShading = 1.0f; + } + + VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + inputAssembly.topology = desc->topology; + // We will use dynamic viewport state. pipe.pVertexInputState = &desc->vis; pipe.pViewportState = &desc->views; pipe.pTessellationState = nullptr; pipe.pDynamicState = &desc->ds; - pipe.pInputAssemblyState = &desc->inputAssembly; - pipe.pMultisampleState = &desc->ms; + pipe.pInputAssemblyState = &inputAssembly; + pipe.pMultisampleState = &ms; pipe.layout = desc->pipelineLayout; pipe.basePipelineHandle = VK_NULL_HANDLE; pipe.basePipelineIndex = 0; @@ -83,8 +110,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR double start = time_now_d(); VkPipeline vkpipeline; VkResult result = vkCreateGraphicsPipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &pipe, nullptr, &vkpipeline); + double taken_ms = (time_now_d() - start) * 1000.0; - INFO_LOG(G3D, "Pipeline creation time: %0.2f ms", (time_now_d() - start) * 1000.0); + if (taken_ms < 0.1) { + DEBUG_LOG(G3D, "Pipeline creation time: %0.2f ms (fast) rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); + } else { + INFO_LOG(G3D, "Pipeline creation time: %0.2f ms rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str()); + } bool success = true; if (result == VK_INCOMPLETE) { @@ -92,30 +124,45 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR // Would really like to log more here, we could probably attach more info to desc. // // At least create a null placeholder to avoid creating over and over if something is broken. - pipeline[rpType]->Post(VK_NULL_HANDLE); + pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); + ERROR_LOG(G3D, "Failed creating graphics pipeline! VK_INCOMPLETE"); + LogCreationFailure(); success = false; } else if (result != VK_SUCCESS) { - pipeline[rpType]->Post(VK_NULL_HANDLE); + pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + LogCreationFailure(); success = false; } else { // Success! - if (!tag.empty()) { - vulkan->SetDebugName(vkpipeline, VK_OBJECT_TYPE_PIPELINE, tag.c_str()); + if (!tag_.empty()) { + vulkan->SetDebugName(vkpipeline, VK_OBJECT_TYPE_PIPELINE, tag_.c_str()); } - pipeline[rpType]->Post(vkpipeline); + pipeline[(size_t)rpType]->Post(vkpipeline); } return success; } -void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { - for (int i = 0; i < RP_TYPE_COUNT; i++) { - if (!pipeline[i]) +void VKRGraphicsPipeline::DestroyVariants(VulkanContext *vulkan, bool msaaOnly) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { + if (!this->pipeline[i]) continue; + if (msaaOnly && (i & (int)RenderPassType::MULTISAMPLE) == 0) + continue; + VkPipeline pipeline = this->pipeline[i]->BlockUntilReady(); - vulkan->Delete().QueueDeletePipeline(pipeline); + // pipeline can be nullptr here, if it failed to compile before. + if (pipeline) { + vulkan->Delete().QueueDeletePipeline(pipeline); + } + this->pipeline[i] = nullptr; } + sampleCount_ = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM; +} + +void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { + DestroyVariants(vulkan, false); vulkan->Delete().QueueCallback([](void *p) { VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; delete pipeline; @@ -124,7 +171,7 @@ void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { u32 VKRGraphicsPipeline::GetVariantsBitmask() const { u32 bitmask = 0; - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (pipeline[i]) { bitmask |= 1 << i; } @@ -132,6 +179,16 @@ u32 VKRGraphicsPipeline::GetVariantsBitmask() const { return bitmask; } +void VKRGraphicsPipeline::LogCreationFailure() const { + ERROR_LOG(G3D, "vs: %s\n[END VS]", desc->vertexShaderSource.c_str()); + ERROR_LOG(G3D, "fs: %s\n[END FS]", desc->fragmentShaderSource.c_str()); + if (desc->geometryShader) { + ERROR_LOG(G3D, "gs: %s\n[END GS]", desc->geometryShaderSource.c_str()); + } + // TODO: Maybe log various other state? + ERROR_LOG(G3D, "======== END OF PIPELINE =========="); +} + bool VKRComputePipeline::Create(VulkanContext *vulkan) { if (!desc) { // Already failed to create this one. @@ -154,173 +211,6 @@ bool VKRComputePipeline::Create(VulkanContext *vulkan) { return success; } -VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, bool createDepthStencilBuffer, const char *tag) : vulkan_(vk), tag_(tag) { - width = _width; - height = _height; - - _dbg_assert_(tag); - - CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag); - if (createDepthStencilBuffer) { - CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag); - } - - UpdateTag(tag); - - // We create the actual framebuffer objects on demand, because some combinations might not make sense. - // Framebuffer objects are just pointers to a set of images, so no biggie. -} - -void VKRFramebuffer::UpdateTag(const char *newTag) { - char name[128]; - snprintf(name, sizeof(name), "fb_color_%s", tag_.c_str()); - vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, name); - vulkan_->SetDebugName(color.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); - if (depth.image) { - snprintf(name, sizeof(name), "fb_depth_%s", tag_.c_str()); - vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name); - vulkan_->SetDebugName(depth.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); - } - for (int rpType = 0; rpType < RP_TYPE_COUNT; rpType++) { - if (framebuf[rpType]) { - snprintf(name, sizeof(name), "fb_%s", tag_.c_str()); - vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name); - } - } -} - -VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) { - if (framebuf[(int)rpType]) { - return framebuf[(int)rpType]; - } - - VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - VkImageView views[2]{}; - - bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT; - - views[0] = color.imageView; - if (hasDepth) { - _dbg_assert_(depth.imageView != VK_NULL_HANDLE); - views[1] = depth.imageView; - } - fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType); - fbci.attachmentCount = hasDepth ? 2 : 1; - fbci.pAttachments = views; - fbci.width = width; - fbci.height = height; - fbci.layers = 1; - - VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]); - _assert_(res == VK_SUCCESS); - - if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) { - vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str()); - } - - return framebuf[(int)rpType]; -} - -VKRFramebuffer::~VKRFramebuffer() { - if (color.imageView) - vulkan_->Delete().QueueDeleteImageView(color.imageView); - if (depth.imageView) - vulkan_->Delete().QueueDeleteImageView(depth.imageView); - if (color.image) { - _dbg_assert_(color.alloc); - vulkan_->Delete().QueueDeleteImageAllocation(color.image, color.alloc); - } - if (depth.image) { - _dbg_assert_(depth.alloc); - vulkan_->Delete().QueueDeleteImageAllocation(depth.image, depth.alloc); - } - if (depth.depthSampleView) - vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView); - for (auto &fb : framebuf) { - if (fb) - vulkan_->Delete().QueueDeleteFramebuffer(fb); - } -} - -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { - VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - ici.arrayLayers = 1; - ici.mipLevels = 1; - ici.extent.width = width; - ici.extent.height = height; - ici.extent.depth = 1; - ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - ici.imageType = VK_IMAGE_TYPE_2D; - ici.samples = VK_SAMPLE_COUNT_1_BIT; - ici.tiling = VK_IMAGE_TILING_OPTIMAL; - ici.format = format; - // Strictly speaking we don't yet need VK_IMAGE_USAGE_SAMPLED_BIT for depth buffers since we do not yet sample depth buffers. - ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - if (color) { - ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - } else { - ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - - VmaAllocationCreateInfo allocCreateInfo{}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - VmaAllocationInfo allocInfo{}; - - VkResult res = vmaCreateImage(vulkan->Allocator(), &ici, &allocCreateInfo, &img.image, &img.alloc, &allocInfo); - _dbg_assert_(res == VK_SUCCESS); - - VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); - - VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; - ivci.format = ici.format; - ivci.image = img.image; - ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; - ivci.subresourceRange.aspectMask = aspects; - ivci.subresourceRange.layerCount = 1; - ivci.subresourceRange.levelCount = 1; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.imageView); - _dbg_assert_(res == VK_SUCCESS); - - // Separate view for texture sampling that only exposes depth. - if (!color) { - ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.depthSampleView); - _dbg_assert_(res == VK_SUCCESS); - } else { - img.depthSampleView = VK_NULL_HANDLE; - } - - VkPipelineStageFlags dstStage; - VkAccessFlagBits dstAccessMask; - switch (initialLayout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - default: - Crash(); - return; - } - - TransitionImageLayout2(cmd, img.image, 0, 1, aspects, - VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, - 0, dstAccessMask); - img.layout = initialLayout; - - img.format = format; - img.tag = tag ? tag : "N/A"; -} - VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan), queueRunner_(vulkan), initTimeMs_("initTimeMs"), @@ -472,23 +362,26 @@ void VulkanRenderManager::CompileThreadFunc() { break; } - if (!toCompile.empty()) { - INFO_LOG(G3D, "Compilation thread has %d pipelines to create", (int)toCompile.size()); - } - + double time = time_now_d(); // TODO: Here we can sort the pending pipelines by vertex and fragment shaders, // and split up further. // Those with the same pairs of shaders should be on the same thread. for (auto &entry : toCompile) { switch (entry.type) { case CompileQueueEntry::Type::GRAPHICS: - entry.graphics->Create(vulkan_, entry.compatibleRenderPass, entry.renderPassType); + entry.graphics->Create(vulkan_, entry.compatibleRenderPass, entry.renderPassType, entry.sampleCount); break; case CompileQueueEntry::Type::COMPUTE: entry.compute->Create(vulkan_); break; } } + + double delta = time_now_d() - time; + if (delta > 0.005f) { + INFO_LOG(G3D, "CompileThreadFunc: Creating %d pipelines took %0.3f ms", (int)toCompile.size(), delta * 1000.0f); + } + queueRunner_.NotifyCompileDone(); } } @@ -611,10 +504,8 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling, bool enableLogProfile // Must be after the fence - this performs deletes. VLOG("PUSH: BeginFrame %d", curFrame); - vulkan_->BeginFrame(enableLogProfiler ? GetInitCmd() : VK_NULL_HANDLE); - insideFrame_ = true; - renderStepOffset_ = 0; + vulkan_->BeginFrame(enableLogProfiler ? GetInitCmd() : VK_NULL_HANDLE); frameData.profile.timestampDescriptions.clear(); if (frameData.profilingEnabled_) { @@ -633,12 +524,12 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() { return frameData_[curFrame].GetInitCmd(vulkan_); } -VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, const char *tag) { - VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(); +VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag) { + VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline(pipelineFlags, tag); _dbg_assert_(desc->vertexShader); _dbg_assert_(desc->fragmentShader); pipeline->desc = desc; - pipeline->tag = tag; + pipeline->desc->AddRef(); if (curRenderStep_) { // The common case pipelinesToCheck_.push_back(pipeline); @@ -655,27 +546,28 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe VKRRenderPass *compatibleRenderPass = queueRunner_.GetRenderPass(key); compileMutex_.lock(); bool needsCompile = false; - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (!(variantBitmask & (1 << i))) continue; RenderPassType rpType = (RenderPassType)i; // Sanity check - don't compile incompatible types (could be caused by corrupt caches, changes in data structures, etc). - if (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) { - if (!RenderPassTypeHasDepth(rpType)) { - WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type"); - continue; - } + if ((pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) && !RenderPassTypeHasDepth(rpType)) { + WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type"); + continue; } - if (pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) { - if (!RenderPassTypeHasInput(rpType)) { - WARN_LOG(G3D, "Not compiling pipeline that requires input attachment, for non input renderpass type"); - continue; - } + if ((pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) && !RenderPassTypeHasInput(rpType)) { + WARN_LOG(G3D, "Not compiling pipeline that requires input attachment, for non input renderpass type"); + continue; + } + // Shouldn't hit this, these should have been filtered elsewhere. However, still a good check to do. + if (sampleCount == VK_SAMPLE_COUNT_1_BIT && RenderPassTypeHasMultisample(rpType)) { + WARN_LOG(G3D, "Not compiling single sample pipeline for a multisampled render pass type"); + continue; } - pipeline->pipeline[rpType] = Promise::CreateEmpty(); - compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType), rpType)); + pipeline->pipeline[i] = Promise::CreateEmpty(); + compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType, sampleCount), rpType, sampleCount)); needsCompile = true; } if (needsCompile) @@ -707,24 +599,43 @@ void VulkanRenderManager::EndCurRenderStep() { // We'll often be able to avoid loading/saving the depth/stencil buffer. curRenderStep_->render.pipelineFlags = curPipelineFlags_; bool depthStencil = (curPipelineFlags_ & PipelineFlags::USES_DEPTH_STENCIL) != 0; - RenderPassType rpType = depthStencil ? RP_TYPE_COLOR_DEPTH : RP_TYPE_COLOR; + RenderPassType rpType = depthStencil ? RenderPassType::HAS_DEPTH : RenderPassType::DEFAULT; + + if (curRenderStep_->render.framebuffer && (rpType & RenderPassType::HAS_DEPTH) && !curRenderStep_->render.framebuffer->HasDepth()) { + WARN_LOG(G3D, "Trying to render with a depth-writing pipeline to a framebuffer without depth: %s", curRenderStep_->render.framebuffer->Tag()); + rpType = RenderPassType::DEFAULT; + } + if (!curRenderStep_->render.framebuffer) { - rpType = RP_TYPE_BACKBUFFER; - } else if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) { - // Not allowed on backbuffers. - rpType = depthStencil ? RP_TYPE_COLOR_DEPTH_INPUT : RP_TYPE_COLOR_INPUT; + rpType = RenderPassType::BACKBUFFER; + } else { + if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) { + // Not allowed on backbuffers. + rpType = depthStencil ? (RenderPassType::HAS_DEPTH | RenderPassType::COLOR_INPUT) : RenderPassType::COLOR_INPUT; + } + // Framebuffers can be stereo, and if so, will control the render pass type to match. + // Pipelines can be mono and render fine to stereo etc, so not checking them here. + // Note that we don't support rendering to just one layer of a multilayer framebuffer! + if (curRenderStep_->render.framebuffer->numLayers > 1) { + rpType = (RenderPassType)(rpType | RenderPassType::MULTIVIEW); + } + + if (curRenderStep_->render.framebuffer->sampleCount != VK_SAMPLE_COUNT_1_BIT) { + rpType = (RenderPassType)(rpType | RenderPassType::MULTISAMPLE); + } } - // TODO: Also add render pass types for depth/stencil-less. VKRRenderPass *renderPass = queueRunner_.GetRenderPass(key); curRenderStep_->render.renderPassType = rpType; + VkSampleCountFlagBits sampleCount = curRenderStep_->render.framebuffer ? curRenderStep_->render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; + compileMutex_.lock(); bool needsCompile = false; for (VKRGraphicsPipeline *pipeline : pipelinesToCheck_) { - if (!pipeline->pipeline[rpType]) { - pipeline->pipeline[rpType] = Promise::CreateEmpty(); - compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType), rpType)); + if (!pipeline->pipeline[(size_t)rpType]) { + pipeline->pipeline[(size_t)rpType] = Promise::CreateEmpty(); + compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType, sampleCount), rpType, sampleCount)); needsCompile = true; } } @@ -889,6 +800,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR data.clear.clearMask = lateClearMask; curRenderStep_->commands.push_back(data); } + + if (invalidationCallback_) { + invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE); + } } bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { @@ -1037,6 +952,7 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); if (!clearMask) return; + // If this is the first drawing command or clears everything, merge it into the pass. int allAspects = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; if (curRenderStep_->render.numDraws == 0 || clearMask == allAspects) { @@ -1048,7 +964,11 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten curRenderStep_->render.stencilLoad = (clearMask & VK_IMAGE_ASPECT_STENCIL_BIT) ? VKRRenderPassLoadAction::CLEAR : VKRRenderPassLoadAction::KEEP; if (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL; + if (curRenderStep_->render.framebuffer && !curRenderStep_->render.framebuffer->HasDepth()) { + WARN_LOG(G3D, "Trying to clear depth/stencil on a non-depth framebuffer: %s", curRenderStep_->render.framebuffer->Tag()); + } else { + curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL; + } } // In case there were commands already. @@ -1175,7 +1095,7 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, steps_.push_back(step); } -VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int attachment) { +VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int layer) { _dbg_assert_(curRenderStep_ != nullptr); // We don't support texturing from stencil, neither do we support texturing from depth|stencil together (nonsensical). @@ -1210,7 +1130,12 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in // Add this pretransition unless we already have it. TransitionRequest rq{ fb, aspectBit, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; curRenderStep_->preTransitions.insert(rq); // Note that insert avoids inserting duplicates. - return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; + + if (layer == -1) { + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.texAllLayersView : fb->depth.texAllLayersView; + } else { + return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.texLayerViews[layer] : fb->depth.texLayerViews[layer]; + } } // Called on main thread. @@ -1278,7 +1203,16 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { if (task.steps.empty() && !frameData.hasAcquired) frameData.skipSwap = true; //queueRunner_.LogSteps(stepsOnThread, false); - queueRunner_.RunSteps(task.steps, frameData, frameDataShared_); + if (IsVREnabled()) { + int passes = GetVRPassesCount(); + for (int i = 0; i < passes; i++) { + PreVRFrameRender(i); + queueRunner_.RunSteps(task.steps, frameData, frameDataShared_, i < passes - 1); + PostVRFrameRender(); + } + } else { + queueRunner_.RunSteps(task.steps, frameData, frameDataShared_); + } switch (task.runType) { case VKRRunType::PRESENT: @@ -1328,7 +1262,9 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { // Called from main thread. void VulkanRenderManager::FlushSync() { - renderStepOffset_ += (int)steps_.size(); + if (invalidationCallback_) { + invalidationCallback_(InvalidationCallbackFlags::COMMAND_BUFFER_STATE); + } int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index a96dd96875..064f1684c9 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -19,55 +19,14 @@ #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Math/math_util.h" #include "Common/GPU/DataFormat.h" +#include "Common/GPU/MiscTypes.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" +#include "Common/GPU/Vulkan/VulkanFramebuffer.h" +#include "Common/GPU/thin3d.h" // Forward declaration VK_DEFINE_HANDLE(VmaAllocation); -// Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine -// to let them have individual non-pooled allocations. Until it's not fine. We'll see. -struct VKRImage { - // These four are "immutable". - VkImage image; - VkImageView imageView; - VkImageView depthSampleView; - VmaAllocation alloc; - VkFormat format; - - // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. - VkImageLayout layout; - - // For debugging. - std::string tag; -}; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); - -class VKRFramebuffer { -public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, bool createDepthStencilBuffer, const char *tag); - ~VKRFramebuffer(); - - VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType); - - int width = 0; - int height = 0; - VKRImage color{}; // color.image is always there. - VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE. - - const char *Tag() const { - return tag_.c_str(); - } - - void UpdateTag(const char *newTag); - - // TODO: Hide. - VulkanContext *vulkan_; -private: - VkFramebuffer framebuf[RP_TYPE_COUNT]{}; - - std::string tag_; -}; - struct BoundingRect { int x1; int y1; @@ -116,7 +75,8 @@ struct BoundingRect { }; // All the data needed to create a graphics pipeline. -struct VKRGraphicsPipelineDesc { +// TODO: Compress this down greatly. +struct VKRGraphicsPipelineDesc : Draw::RefCountedObject { VkPipelineCache pipelineCache = VK_NULL_HANDLE; VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; VkPipelineColorBlendAttachmentState blend0{}; @@ -124,14 +84,19 @@ struct VKRGraphicsPipelineDesc { VkDynamicState dynamicStates[6]{}; VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; - VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; // Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish. Promise *vertexShader = nullptr; Promise *fragmentShader = nullptr; Promise *geometryShader = nullptr; - VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + // These are for pipeline creation failure logging. + // TODO: Store pointers to the string instead? Feels iffy but will probably work. + std::string vertexShaderSource; + std::string fragmentShaderSource; + std::string geometryShaderSource; + + VkPrimitiveTopology topology; VkVertexInputAttributeDescription attrs[8]{}; VkVertexInputBindingDescription ibd{}; VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; @@ -152,22 +117,34 @@ struct VKRComputePipelineDesc { // Wrapped pipeline. Doesn't own desc. struct VKRGraphicsPipeline { + VKRGraphicsPipeline(PipelineFlags flags, const char *tag) : flags_(flags), tag_(tag) {} ~VKRGraphicsPipeline() { - for (int i = 0; i < RP_TYPE_COUNT; i++) { + for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { delete pipeline[i]; } + if (desc) + desc->Release(); } - bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType); + bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount); + + void DestroyVariants(VulkanContext *vulkan, bool msaaOnly); // This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this. void QueueForDeletion(VulkanContext *vulkan); u32 GetVariantsBitmask() const; - VKRGraphicsPipelineDesc *desc = nullptr; // not owned! - Promise *pipeline[RP_TYPE_COUNT]{}; - std::string tag; + void LogCreationFailure() const; + + VKRGraphicsPipelineDesc *desc = nullptr; + Promise *pipeline[(size_t)RenderPassType::TYPE_COUNT]{}; + + VkSampleCountFlagBits SampleCount() const { return sampleCount_; } +private: + std::string tag_; + PipelineFlags flags_; + VkSampleCountFlagBits sampleCount_ = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM; }; struct VKRComputePipeline { @@ -185,9 +162,9 @@ struct VKRComputePipeline { }; struct CompileQueueEntry { - CompileQueueEntry(VKRGraphicsPipeline *p, VkRenderPass _compatibleRenderPass, RenderPassType _renderPassType) - : type(Type::GRAPHICS), graphics(p), compatibleRenderPass(_compatibleRenderPass), renderPassType(_renderPassType) {} - CompileQueueEntry(VKRComputePipeline *p) : type(Type::COMPUTE), compute(p), renderPassType(RP_TYPE_COLOR_DEPTH) {} + CompileQueueEntry(VKRGraphicsPipeline *p, VkRenderPass _compatibleRenderPass, RenderPassType _renderPassType, VkSampleCountFlagBits _sampleCount) + : type(Type::GRAPHICS), graphics(p), compatibleRenderPass(_compatibleRenderPass), renderPassType(_renderPassType), sampleCount(_sampleCount) {} + CompileQueueEntry(VKRComputePipeline *p) : type(Type::COMPUTE), compute(p), renderPassType(RenderPassType::HAS_DEPTH), sampleCount(VK_SAMPLE_COUNT_1_BIT) {} // renderpasstype here shouldn't matter enum class Type { GRAPHICS, COMPUTE, @@ -197,6 +174,7 @@ struct CompileQueueEntry { RenderPassType renderPassType; VKRGraphicsPipeline *graphics = nullptr; VKRComputePipeline *compute = nullptr; + VkSampleCountFlagBits sampleCount; }; class VulkanRenderManager { @@ -211,7 +189,11 @@ public: // Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown. void Wipe(); - // This starts a new step containing a render pass. + void SetInvalidationCallback(InvalidationCallback callback) { + invalidationCallback_ = callback; + } + + // This starts a new step containing a render pass (unless it can be trivially merged into the previous one, which is pretty common). // // After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce // making any new render state changes or draw calls. @@ -230,7 +212,9 @@ public: // Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface // as the other backends, even though there's no actual binding happening here. - VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits, int attachment); + // For layer, we use the same convention as thin3d, where layer = -1 means all layers together. For texturing, that means that you + // get an array texture view. + VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits, int layer); void BindCurrentFramebufferAsInputAttachment0(VkImageAspectFlags aspectBits); @@ -245,7 +229,7 @@ public: // We delay creating pipelines until the end of the current render pass, so we can create the right type immediately. // Unless a variantBitmask is passed in, in which case we can just go ahead. // WARNING: desc must stick around during the lifetime of the pipeline! It's not enough to build it on the stack and drop it. - VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, const char *tag); + VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag); VKRComputePipeline *CreateComputePipeline(VKRComputePipelineDesc *desc); void NudgeCompilerThread() { @@ -254,6 +238,16 @@ public: compileMutex_.unlock(); } + // Mainly used to bind the frame-global desc set. + // Can be done before binding a pipeline, so not asserting on that. + void BindDescriptorSet(int setNumber, VkDescriptorSet set, VkPipelineLayout pipelineLayout) { + VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET }; + data.bindDescSet.setNumber = setNumber; + data.bindDescSet.set = set; + data.bindDescSet.pipelineLayout = pipelineLayout; + curRenderStep_->commands.push_back(data); + } + void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); @@ -261,6 +255,10 @@ public: pipelinesToCheck_.push_back(pipeline); data.graphics_pipeline.pipeline = pipeline; data.graphics_pipeline.pipelineLayout = pipelineLayout; + // This can be used to debug cases where depth/stencil rendering is used on color-only framebuffers. + // if ((flags & PipelineFlags::USES_DEPTH_STENCIL) && curRenderStep_->render.framebuffer && !curRenderStep_->render.framebuffer->HasDepth()) { + // DebugBreak(); + // } curPipelineFlags_ |= flags; curRenderStep_->commands.push_back(data); } @@ -435,12 +433,6 @@ public: VkCommandBuffer GetInitCmd(); - // Gets a frame-unique ID of the current step being recorded. Can be used to figure out - // when the current step has changed, which means the caller will need to re-record its state. - int GetCurrentStepId() const { - return renderStepOffset_ + (int)steps_.size(); - } - bool CreateBackbuffers(); void DestroyBackbuffers(); @@ -470,6 +462,8 @@ public: return outOfDateFrames_ > VulkanContext::MAX_INFLIGHT_FRAMES; } + void Invalidate(InvalidationFlags flags); + void ResetStats(); private: @@ -480,7 +474,6 @@ private: void DrainCompileQueue(); void Run(VKRRenderThreadTask &task); - void BeginSubmitFrame(int frame); // Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot). void FlushSync(); @@ -508,7 +501,6 @@ private: bool run_ = false; // This is the offset within this frame, in case of a mid-frame sync. - int renderStepOffset_ = 0; VKRStep *curRenderStep_ = nullptr; bool curStepHasViewport_ = false; bool curStepHasScissor_ = false; @@ -547,4 +539,6 @@ private: SimpleStat initTimeMs_; SimpleStat totalGPUTimeMs_; SimpleStat renderCPUTimeMs_; + + std::function invalidationCallback_; }; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 7d3b0e8218..fbb5fbb3e8 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -35,15 +35,22 @@ #include "Core/Config.h" -// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point. -// binding 0 - uniform data -// binding 1 - sampler -// binding 2 - sampler -// -// Vertex data lives in a separate namespace (location = 0, 1, etc) - #include "Common/GPU/Vulkan/VulkanLoader.h" +// We support a frame-global descriptor set, which can be optionally used by other code, +// but is not directly used by thin3d. It has to be defined here though, be in set 0 +// and specified in every pipeline layout, otherwise it can't sit undisturbed when other +// descriptor sets are bound on top. + +// For descriptor set 1, we use a simple descriptor set for all thin3d rendering: 1 UBO binding point, 3 combined texture/samples. +// +// binding 0 - uniform buffer +// binding 1 - texture/sampler +// binding 2 - texture/sampler +// binding 3 - texture/sampler +// +// Vertex data lives in a separate namespace (location = 0, 1, etc). + using namespace PPSSPP_VK; namespace Draw { @@ -196,7 +203,10 @@ public: DEBUG_LOG(G3D, "Queueing %s (shmodule %p) for release", tag_.c_str(), module_); VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } Promise *Get() const { return module_; } @@ -235,7 +245,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con #endif VkShaderModule shaderModule = VK_NULL_HANDLE; - if (vulkan->CreateShaderModule(spirv, &shaderModule, vkstage_ == VK_SHADER_STAGE_VERTEX_BIT ? "thin3d_vs" : "thin3d_fs")) { + if (vulkan->CreateShaderModule(spirv, &shaderModule, tag_.c_str())) { module_ = Promise::AlreadyDone(shaderModule); ok_ = true; } else { @@ -257,6 +267,7 @@ public: VKPipeline(VulkanContext *vulkan, size_t size, PipelineFlags _flags, const char *tag) : vulkan_(vulkan), flags(_flags), tag_(tag) { uboSize_ = (int)size; ubo_ = new uint8_t[uboSize_]; + vkrDesc = new VKRGraphicsPipelineDesc(); } ~VKPipeline() { DEBUG_LOG(G3D, "Queueing %s (pipeline) for release", tag_.c_str()); @@ -267,9 +278,11 @@ public: dep->Release(); } delete[] ubo_; + vkrDesc->Release(); } void SetDynamicUniformData(const void *data, size_t size) { + _dbg_assert_(size <= uboSize_); memcpy(ubo_, data, size); } @@ -283,7 +296,7 @@ public: } VKRGraphicsPipeline *pipeline = nullptr; - VKRGraphicsPipelineDesc vkrDesc; + VKRGraphicsPipelineDesc *vkrDesc = nullptr; PipelineFlags flags; std::vector deps; @@ -335,12 +348,16 @@ public: VkImageView GetImageView() { if (vkTex_) { - vkTex_->Touch(); return vkTex_->GetImageView(); - } else { - // This would be bad. - return VK_NULL_HANDLE; } + return VK_NULL_HANDLE; // This would be bad. + } + + VkImageView GetImageArrayView() { + if (vkTex_) { + return vkTex_->GetImageArrayView(); + } + return VK_NULL_HANDLE; // This would be bad. } private: @@ -365,7 +382,7 @@ class VKFramebuffer; class VKContext : public DrawContext { public: VKContext(VulkanContext *vulkan); - virtual ~VKContext(); + ~VKContext(); void DebugAnnotate(const char *annotation) override; @@ -405,10 +422,7 @@ public: // These functions should be self explanatory. void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; - Framebuffer *GetCurrentRenderTarget() override { - return (Framebuffer *)curFramebuffer_.ptr; - } - void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; + void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override; void BindCurrentFramebufferForColorInput() override; void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; @@ -419,7 +433,7 @@ public: void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override; void BindSamplerStates(int start, int count, SamplerState **state) override; - void BindTextures(int start, int count, Texture **textures) override; + void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override; void BindNativeTexture(int sampler, void *nativeTexture) override; void BindPipeline(Pipeline *pipeline) override { @@ -487,14 +501,14 @@ public: void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override; - int GetCurrentStepId() const override { - return renderManager_.GetCurrentStepId(); - } - - void InvalidateCachedState() override; + void Invalidate(InvalidationFlags flags) override; void InvalidateFramebuffer(FBInvalidationStage stage, uint32_t channels) override; + void SetInvalidationCallback(InvalidationCallback callback) override { + renderManager_.SetInvalidationCallback(callback); + } + private: VulkanTexture *GetNullTexture(); VulkanContext *vulkan_ = nullptr; @@ -510,6 +524,7 @@ private: int curIBufferOffset_ = 0; VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE; + VkDescriptorSetLayout frameDescSetLayout_ = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE; VkPipelineCache pipelineCache_ = VK_NULL_HANDLE; AutoRef curFramebuffer_; @@ -524,6 +539,7 @@ private: AutoRef boundTextures_[MAX_BOUND_TEXTURES]; AutoRef boundSamplers_[MAX_BOUND_TEXTURES]; VkImageView boundImageView_[MAX_BOUND_TEXTURES]{}; + TextureBindFlags boundTextureFlags_[MAX_BOUND_TEXTURES]; struct FrameData { FrameData() : descriptorPool("VKContext", false) { @@ -579,6 +595,8 @@ static int GetBpp(VkFormat format) { static VkFormat DataFormatToVulkan(DataFormat format) { switch (format) { case DataFormat::D16: return VK_FORMAT_D16_UNORM; + case DataFormat::D16_S8: return VK_FORMAT_D16_UNORM_S8_UINT; + case DataFormat::D24_S8: return VK_FORMAT_D24_UNORM_S8_UINT; case DataFormat::D32F: return VK_FORMAT_D32_SFLOAT; case DataFormat::D32F_S8: return VK_FORMAT_D32_SFLOAT_S8_UINT; case DataFormat::S8: return VK_FORMAT_S8_UINT; @@ -637,8 +655,7 @@ static inline VkSamplerAddressMode AddressModeToVulkan(Draw::TextureAddressMode VulkanTexture *VKContext::GetNullTexture() { if (!nullTexture_) { VkCommandBuffer cmdInit = renderManager_.GetInitCmd(); - nullTexture_ = new VulkanTexture(vulkan_); - nullTexture_->SetTag("Null"); + nullTexture_ = new VulkanTexture(vulkan_, "Null"); int w = 8; int h = 8; nullTexture_->CreateDirect(cmdInit, w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -654,8 +671,6 @@ VulkanTexture *VKContext::GetNullTexture() { } nullTexture_->UploadMip(cmdInit, 0, w, h, 0, bindBuf, bindOffset, w); nullTexture_->EndCreate(cmdInit, false, VK_PIPELINE_STAGE_TRANSFER_BIT); - } else { - nullTexture_->Touch(); } return nullTexture_; } @@ -668,6 +683,7 @@ public: s.addressModeV = AddressModeToVulkan(desc.wrapV); s.addressModeW = AddressModeToVulkan(desc.wrapW); s.anisotropyEnable = desc.maxAniso > 1.0f; + s.maxAnisotropy = desc.maxAniso; s.magFilter = desc.magFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; s.minFilter = desc.minFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; s.mipmapMode = desc.mipFilter == TextureFilter::LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; @@ -721,10 +737,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur width_ = desc.width; height_ = desc.height; depth_ = desc.depth; - vkTex_ = new VulkanTexture(vulkan_); - if (desc.tag) { - vkTex_->SetTag(desc.tag); - } + vkTex_ = new VulkanTexture(vulkan_, desc.tag); VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); int bytesPerPixel = bpp / 8; @@ -771,34 +784,58 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur return true; } +static DataFormat DataFormatFromVulkanDepth(VkFormat fmt) { + switch (fmt) { + case VK_FORMAT_D24_UNORM_S8_UINT: + return DataFormat::D24_S8; + case VK_FORMAT_D16_UNORM: + return DataFormat::D16; + case VK_FORMAT_D32_SFLOAT: + return DataFormat::D32F; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return DataFormat::D32F_S8; + case VK_FORMAT_D16_UNORM_S8_UINT: + return DataFormat::D16_S8; + default: + break; + } + + return DataFormat::UNDEFINED; +} + VKContext::VKContext(VulkanContext *vulkan) : vulkan_(vulkan), renderManager_(vulkan) { shaderLanguageDesc_.Init(GLSL_VULKAN); VkFormat depthStencilFormat = vulkan->GetDeviceInfo().preferredDepthStencilFormat; - caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.samplerAnisotropy != 0; - caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.geometryShader != 0; - caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.tessellationShader != 0; - caps_.multiViewport = vulkan->GetDeviceFeatures().enabled.multiViewport != 0; - caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.dualSrcBlend != 0; - caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.depthClamp != 0; - caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderClipDistance != 0; - caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderCullDistance != 0; + caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.standard.samplerAnisotropy != 0; + caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.geometryShader != 0; + caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.tessellationShader != 0; + caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.standard.dualSrcBlend != 0; + caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.standard.depthClamp != 0; + caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderClipDistance != 0; + caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderCullDistance != 0; caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat; caps_.framebufferStencilBlitSupported = caps_.framebufferDepthBlitSupported; caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case. - caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. + // This doesn't affect what depth/stencil format is actually used, see VulkanQueueRunner. + caps_.preferredDepthBufferFormat = DataFormatFromVulkanDepth(vulkan->GetDeviceInfo().preferredDepthStencilFormat); caps_.texture3DSupported = true; caps_.textureDepthSupported = true; caps_.fragmentShaderInt32Supported = true; caps_.textureNPOTFullySupported = true; caps_.fragmentShaderDepthWriteSupported = true; + caps_.fragmentShaderStencilWriteSupported = vulkan->Extensions().EXT_shader_stencil_export; caps_.blendMinMaxSupported = true; - caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.logicOp != 0; + caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0; + caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0; + caps_.sampleRateShadingSupported = vulkan->GetDeviceFeatures().enabled.standard.sampleRateShading != 0; + + const auto &limits = vulkan->GetPhysicalDeviceProperties().properties.limits; auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties; @@ -809,7 +846,47 @@ VKContext::VKContext(VulkanContext *vulkan) case VULKAN_VENDOR_NVIDIA: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; case VULKAN_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::VENDOR_QUALCOMM; break; case VULKAN_VENDOR_INTEL: caps_.vendor = GPUVendor::VENDOR_INTEL; break; - default: caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; + case VULKAN_VENDOR_APPLE: caps_.vendor = GPUVendor::VENDOR_APPLE; break; + default: + WARN_LOG(G3D, "Unknown vendor ID %08x", deviceProps.vendorID); + caps_.vendor = GPUVendor::VENDOR_UNKNOWN; + break; + } + + switch (caps_.vendor) { + case GPUVendor::VENDOR_ARM: + case GPUVendor::VENDOR_IMGTEC: + case GPUVendor::VENDOR_QUALCOMM: + caps_.isTilingGPU = true; + break; + default: + caps_.isTilingGPU = false; + break; + } + + // Hide D3D9 when we know it likely won't work well. +#if PPSSPP_PLATFORM(WINDOWS) + caps_.supportsD3D9 = true; + if (!strcmp(deviceProps.deviceName, "Intel(R) Iris(R) Xe Graphics")) { + caps_.supportsD3D9 = false; + } +#endif + + // VkSampleCountFlagBits is arranged correctly for our purposes. + // Only support MSAA levels that have support for all three of color, depth, stencil. + if (!caps_.isTilingGPU) { + // Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess + // of compatibility reports, so we'll just disable multisampling in this case for now. + // There are potential workarounds for devices that don't support it, but those are nearly non-existent now. + const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; + if (vulkan->Extensions().KHR_depth_stencil_resolve && + ((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) { + caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); + } else { + caps_.multiSampleLevelsMask = 1; + } + } else { + caps_.multiSampleLevelsMask = 1; } if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { @@ -822,7 +899,9 @@ VKContext::VKContext(VulkanContext *vulkan) } // Color write mask not masking write in certain scenarios with a depth test, see #10421. // Known still present on driver 0x80180000 and Adreno 5xx (possibly more.) - bugs_.Infest(Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST); + // Known working on driver 0x801EA000 and Adreno 620. + if (deviceProps.driverVersion < 0x801EA000 || deviceProps.deviceID < 0x06000000) + bugs_.Infest(Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST); // Trying to follow all the rules in https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies // and https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#renderpass-feedbackloop, but still it doesn't @@ -916,13 +995,25 @@ VKContext::VKContext(VulkanContext *vulkan) VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_); _assert_(VK_SUCCESS == res); + VkDescriptorSetLayoutBinding frameBindings[1]{}; + frameBindings[0].descriptorCount = 1; + frameBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + frameBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + frameBindings[0].binding = 0; + + dsl.bindingCount = ARRAY_SIZE(frameBindings); + dsl.pBindings = frameBindings; + res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &frameDescSetLayout_); + _dbg_assert_(VK_SUCCESS == res); + vulkan_->SetDebugName(descriptorSetLayout_, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "thin3d_d_layout"); VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout setLayouts[2] = { frameDescSetLayout_, descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(setLayouts); + pl.pSetLayouts = setLayouts; res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_); _assert_(VK_SUCCESS == res); @@ -942,6 +1033,7 @@ VKContext::~VKContext() { delete frame_[i].pushBuffer; } vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); + vulkan_->Delete().QueueDeleteDescriptorSetLayout(frameDescSetLayout_); vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_); vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_); } @@ -969,20 +1061,22 @@ void VKContext::EndFrame() { push_ = nullptr; // Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things). - InvalidateCachedState(); + Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } -void VKContext::InvalidateCachedState() { - curPipeline_ = nullptr; +void VKContext::Invalidate(InvalidationFlags flags) { + if (flags & InvalidationFlags::CACHED_RENDER_STATE) { + curPipeline_ = nullptr; - for (auto &view : boundImageView_) { - view = VK_NULL_HANDLE; - } - for (auto &sampler : boundSamplers_) { - sampler = nullptr; - } - for (auto &texture : boundTextures_) { - texture = nullptr; + for (auto &view : boundImageView_) { + view = VK_NULL_HANDLE; + } + for (auto &sampler : boundSamplers_) { + sampler = nullptr; + } + for (auto &texture : boundTextures_) { + texture = nullptr; + } } } @@ -996,7 +1090,11 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { FrameData *frame = &frame_[vulkan_->GetCurFrame()]; for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) { - key.imageViews_[i] = boundTextures_[i] ? boundTextures_[i]->GetImageView() : boundImageView_[i]; + if (boundTextures_[i]) { + key.imageViews_[i] = (boundTextureFlags_[i] & TextureBindFlags::VULKAN_BIND_ARRAY) ? boundTextures_[i]->GetImageArrayView() : boundTextures_[i]->GetImageView(); + } else { + key.imageViews_[i] = boundImageView_[i]; + } key.samplers_[i] = boundSamplers_[i]; } key.buffer_ = buf; @@ -1006,7 +1104,7 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) { return iter->second; } - VkDescriptorSet descSet = frame->descriptorPool.Allocate(1, &descriptorSetLayout_); + VkDescriptorSet descSet = frame->descriptorPool.Allocate(1, &descriptorSetLayout_, "thin3d_descset"); if (descSet == VK_NULL_HANDLE) { ERROR_LOG(G3D, "GetOrCreateDescriptorSet failed"); return VK_NULL_HANDLE; @@ -1077,7 +1175,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char VKPipeline *pipeline = new VKPipeline(vulkan_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), pipelineFlags, tag); - VKRGraphicsPipelineDesc &gDesc = pipeline->vkrDesc; + VKRGraphicsPipelineDesc &gDesc = *pipeline->vkrDesc; std::vector stages; stages.resize(desc.shaders.size()); @@ -1097,16 +1195,12 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char } } - if (input) { - for (int i = 0; i < (int)input->bindings.size(); i++) { - pipeline->stride[i] = input->bindings[i].stride; - } - } else { - pipeline->stride[0] = 0; - } - _dbg_assert_(input->bindings.size() == 1); + _dbg_assert_(input && input->bindings.size() == 1); _dbg_assert_((int)input->attributes.size() == (int)input->visc.vertexAttributeDescriptionCount); + for (int i = 0; i < (int)input->bindings.size(); i++) { + pipeline->stride[i] = input->bindings[i].stride; + } gDesc.ibd = input->bindings[0]; for (size_t i = 0; i < input->attributes.size(); i++) { gDesc.attrs[i] = input->attributes[i]; @@ -1125,7 +1219,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char raster->ToVulkan(&gDesc.rs); // Copy bindings from input layout. - gDesc.inputAssembly.topology = primToVK[(int)desc.prim]; + gDesc.topology = primToVK[(int)desc.prim]; // We treat the three stencil states as a unit in other places, so let's do that here too. const VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK }; @@ -1135,9 +1229,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char } gDesc.ds.pDynamicStates = gDesc.dynamicStates; - gDesc.ms.pSampleMask = nullptr; - gDesc.ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - gDesc.views.viewportCount = 1; gDesc.views.scissorCount = 1; gDesc.views.pViewports = nullptr; // dynamic @@ -1148,7 +1239,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&gDesc.rs); - pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << RP_TYPE_BACKBUFFER, tag ? tag : "thin3d"); + pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, tag ? tag : "thin3d"); if (desc.uniformDesc) { pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; @@ -1278,7 +1369,7 @@ public: VKBuffer(size_t size, uint32_t flags) : dataSize_(size) { data_ = new uint8_t[size]; } - ~VKBuffer() override { + ~VKBuffer() { delete[] data_; } @@ -1298,15 +1389,32 @@ void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, memcpy(buf->data_ + offset, data, size); } -void VKContext::BindTextures(int start, int count, Texture **textures) { +void VKContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) { _assert_(start + count <= MAX_BOUND_TEXTURES); for (int i = start; i < start + count; i++) { + _dbg_assert_(i >= 0 && i < MAX_BOUND_TEXTURES); boundTextures_[i] = static_cast(textures[i - start]); - boundImageView_[i] = boundTextures_[i] ? boundTextures_[i]->GetImageView() : GetNullTexture()->GetImageView(); + boundTextureFlags_[i] = flags; + if (boundTextures_[i]) { + // If a texture is bound, we set these up in GetOrCreateDescriptorSet too. + // But we might need to set the view here anyway so it can be queried using GetNativeObject. + if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) { + boundImageView_[i] = boundTextures_[i]->GetImageArrayView(); + } else { + boundImageView_[i] = boundTextures_[i]->GetImageView(); + } + } else { + if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) { + boundImageView_[i] = GetNullTexture()->GetImageArrayView(); + } else { + boundImageView_[i] = GetNullTexture()->GetImageView(); + } + } } } void VKContext::BindNativeTexture(int sampler, void *nativeTexture) { + _dbg_assert_(sampler >= 0 && sampler < MAX_BOUND_TEXTURES); boundTextures_[sampler] = nullptr; boundImageView_[sampler] = (VkImageView)nativeTexture; } @@ -1414,8 +1522,8 @@ void AddFeature(std::vector &features, const char *name, VkBool32 a } std::vector VKContext::GetFeatureList() const { - const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available; - const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled; + const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available.standard; + const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled.standard; std::vector features; AddFeature(features, "dualSrcBlend", available.dualSrcBlend, enabled.dualSrcBlend); @@ -1434,6 +1542,9 @@ std::vector VKContext::GetFeatureList() const { AddFeature(features, "occlusionQueryPrecise", available.occlusionQueryPrecise, enabled.occlusionQueryPrecise); AddFeature(features, "multiDrawIndirect", available.multiDrawIndirect, enabled.multiDrawIndirect); + AddFeature(features, "multiview", vulkan_->GetDeviceFeatures().available.multiview.multiview, vulkan_->GetDeviceFeatures().enabled.multiview.multiview); + AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader); + features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat)); return features; @@ -1479,14 +1590,16 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const { // use this frame's init command buffer. class VKFramebuffer : public Framebuffer { public: - VKFramebuffer(VKRFramebuffer *fb) : buf_(fb) { + VKFramebuffer(VKRFramebuffer *fb, int multiSampleLevel) : buf_(fb) { _assert_msg_(fb, "Null fb in VKFramebuffer constructor"); width_ = fb->width; height_ = fb->height; + layers_ = fb->numLayers; + multiSampleLevel_ = multiSampleLevel; } ~VKFramebuffer() { _assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?"); - buf_->vulkan_->Delete().QueueCallback([](void *fb) { + buf_->Vulkan()->Delete().QueueCallback([](void *fb) { VKRFramebuffer *vfb = static_cast(fb); delete vfb; }, buf_); @@ -1501,9 +1614,14 @@ private: }; Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { + _assert_(desc.multiSampleLevel >= 0); + _assert_(desc.numLayers > 0); + _assert_(desc.width > 0); + _assert_(desc.height > 0); + VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.z_stencil, desc.tag); - return new VKFramebuffer(vkrfb); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag); + return new VKFramebuffer(vkrfb, desc.multiSampleLevel); } void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) { @@ -1563,9 +1681,9 @@ void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPass curFramebuffer_ = fb; } -void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { +void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) { VKFramebuffer *fb = (VKFramebuffer *)fbo; - _assert_(binding < MAX_BOUND_TEXTURES); + _assert_(binding >= 0 && binding < MAX_BOUND_TEXTURES); // TODO: There are cases where this is okay, actually. But requires layout transitions and stuff - // we're not ready for this. @@ -1583,8 +1701,9 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne _assert_(false); break; } - boundTextures_[binding] = nullptr; - boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment); + + boundTextures_[binding].clear(); + boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, layer); } void VKContext::BindCurrentFramebufferForColorInput() { @@ -1645,10 +1764,19 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { return (uint64_t)(uintptr_t)&renderManager_; case NativeObject::NULL_IMAGEVIEW: return (uint64_t)GetNullTexture()->GetImageView(); + case NativeObject::NULL_IMAGEVIEW_ARRAY: + return (uint64_t)GetNullTexture()->GetImageArrayView(); case NativeObject::TEXTURE_VIEW: return (uint64_t)(((VKTexture *)srcObject)->GetImageView()); - case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW: - return (uint64_t)curFramebuffer_->GetFB()->color.imageView; + case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS: + return (uint64_t)curFramebuffer_->GetFB()->color.texAllLayersView; + case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT: + return (uint64_t)curFramebuffer_->GetFB()->GetRTView(); + case NativeObject::FRAME_DATA_DESC_SET_LAYOUT: + return (uint64_t)frameDescSetLayout_; + case NativeObject::THIN3D_PIPELINE_LAYOUT: + return (uint64_t)pipelineLayout_; + default: Crash(); return 0; diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index ac2daa68c7..0ffd9e6b5b 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -46,6 +46,7 @@ size_t DataFormatSizeInBytes(DataFormat fmt) { case DataFormat::S8: return 1; case DataFormat::D16: return 2; + case DataFormat::D16_S8: return 3; case DataFormat::D24_S8: return 4; case DataFormat::D32F: return 4; // Or maybe 8... @@ -56,9 +57,32 @@ size_t DataFormatSizeInBytes(DataFormat fmt) { } } +const char *DataFormatToString(DataFormat fmt) { + switch (fmt) { + case DataFormat::R8_UNORM: return "R8_UNORM"; + case DataFormat::R8G8_UNORM: return "R8G8_UNORM"; + case DataFormat::R8G8B8A8_UNORM: return "R8G8B8A8_UNORM"; + case DataFormat::B8G8R8A8_UNORM: return "B8G8R8A8_UNORM"; + case DataFormat::R16_UNORM: return "R16_UNORM"; + case DataFormat::R16_FLOAT: return "R16_FLOAT"; + case DataFormat::R32_FLOAT: return "R32_FLOAT"; + + case DataFormat::S8: return "S8"; + case DataFormat::D16: return "D16"; + case DataFormat::D16_S8: return "D16_S8"; + case DataFormat::D24_S8: return "D24_S8"; + case DataFormat::D32F: return "D32F"; + case DataFormat::D32F_S8: return "D32F_S8"; + + default: + return "(N/A)"; + } +} + bool DataFormatIsDepthStencil(DataFormat fmt) { switch (fmt) { case DataFormat::D16: + case DataFormat::D16_S8: case DataFormat::D24_S8: case DataFormat::S8: case DataFormat::D32F: @@ -137,7 +161,7 @@ static const std::vector fsTexCol = { "layout(location = 0) in vec4 oColor0;\n" "layout(location = 1) in vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0;\n" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n" } }; @@ -181,7 +205,7 @@ static const std::vector fsTexColRBSwizzle = { "layout(location = 0) in vec4 oColor0;\n" "layout(location = 1) in vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0\n;" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0).bgra * oColor0; }\n" } }; @@ -270,7 +294,7 @@ static const std::vector vsCol = { R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (std140, set = 0, binding = 0) uniform bufferVals { +layout (std140, set = 1, binding = 0) uniform bufferVals { mat4 WorldViewProj; vec2 TintSaturation; } myBufferVals; @@ -416,7 +440,7 @@ VS_OUTPUT main(VS_INPUT input) { R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (std140, set = 0, binding = 0) uniform bufferVals { +layout (std140, set = 1, binding = 0) uniform bufferVals { mat4 WorldViewProj; vec2 TintSaturation; } myBufferVals; @@ -712,6 +736,8 @@ const char *Bugs::GetBugName(uint32_t bug) { case RASPBERRY_SHADER_COMP_HANG: return "RASPBERRY_SHADER_COMP_HANG"; case MALI_CONSTANT_LOAD_BUG: return "MALI_CONSTANT_LOAD_BUG"; case SUBPASS_FEEDBACK_BROKEN: return "SUBPASS_FEEDBACK_BROKEN"; + case GEOMETRY_SHADERS_SLOW_OR_BROKEN: return "GEOMETRY_SHADERS_SLOW_OR_BROKEN"; + case ADRENO_RESOURCE_DEADLOCK: return "ADRENO_RESOURCE_DEADLOCK"; default: return "(N/A)"; } } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 8c440deb04..5d68541f3e 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -13,8 +13,10 @@ #include #include +#include "Common/Common.h" #include "Common/GPU/DataFormat.h" #include "Common/GPU/Shader.h" +#include "Common/GPU/MiscTypes.h" #include "Common/Data/Collections/Slice.h" namespace Lin { @@ -241,12 +243,16 @@ enum class NativeObject { BACKBUFFER_DEPTH_TEX, FEATURE_LEVEL, INIT_COMMANDBUFFER, - BOUND_TEXTURE0_IMAGEVIEW, - BOUND_TEXTURE1_IMAGEVIEW, - BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW, + BOUND_TEXTURE0_IMAGEVIEW, // Layer etc depends on how you bound it... + BOUND_TEXTURE1_IMAGEVIEW, // Layer etc depends on how you bound it... + BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS, + BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT, RENDER_MANAGER, TEXTURE_VIEW, NULL_IMAGEVIEW, + NULL_IMAGEVIEW_ARRAY, + FRAME_DATA_DESC_SET_LAYOUT, + THIN3D_PIPELINE_LAYOUT, }; enum FBChannel { @@ -293,7 +299,8 @@ struct FramebufferDesc { int width; int height; int depth; - int numColorAttachments; + int numLayers; + int multiSampleLevel; // 0 = 1xaa, 1 = 2xaa, and so on. bool z_stencil; const char *tag; // For graphics debuggers }; @@ -334,6 +341,7 @@ public: MALI_CONSTANT_LOAD_BUG = 9, SUBPASS_FEEDBACK_BROKEN = 10, GEOMETRY_SHADERS_SLOW_OR_BROKEN = 11, + ADRENO_RESOURCE_DEADLOCK = 12, MAX_BUG, }; @@ -388,6 +396,9 @@ struct AutoRef { *this = p.ptr; return *this; } + bool operator !=(const AutoRef &p) const { + return ptr != p.ptr; + } T *operator->() const { return ptr; @@ -395,6 +406,16 @@ struct AutoRef { operator T *() { return ptr; } + operator bool() const { + return ptr != nullptr; + } + + void clear() { + if (ptr) { + ptr->Release(); + ptr = nullptr; + } + } T *ptr = nullptr; }; @@ -415,9 +436,12 @@ class Framebuffer : public RefCountedObject { public: int Width() { return width_; } int Height() { return height_; } + int Layers() { return layers_; } + int MultiSampleLevel() { return multiSampleLevel_; } + virtual void UpdateTag(const char *tag) {} protected: - int width_ = -1, height_ = -1; + int width_ = -1, height_ = -1, layers_ = 1, multiSampleLevel_ = 0; }; class Buffer : public RefCountedObject { @@ -459,10 +483,7 @@ public: virtual ShaderStage GetStage() const = 0; }; -class Pipeline : public RefCountedObject { -public: - virtual ~Pipeline() {} -}; +class Pipeline : public RefCountedObject { }; class RasterState : public RefCountedObject {}; @@ -534,7 +555,6 @@ struct DeviceCaps { bool depthRangeMinusOneToOne; // OpenGL style depth bool geometryShaderSupported; bool tesselationShaderSupported; - bool multiViewport; bool dualSourceBlend; bool logicOpSupported; bool depthClampSupported; @@ -551,9 +571,17 @@ struct DeviceCaps { bool fragmentShaderInt32Supported; bool textureNPOTFullySupported; bool fragmentShaderDepthWriteSupported; + bool fragmentShaderStencilWriteSupported; bool textureDepthSupported; bool blendMinMaxSupported; + bool multiViewSupported; + bool isTilingGPU; // This means that it benefits from correct store-ops, msaa without backing memory, etc. + bool sampleRateShadingSupported; + // From the other backends, we can detect if D3D9 support is known bad (like on Xe) and disable it. + bool supportsD3D9; + + u32 multiSampleLevelsMask; // Bit n is set if (1 << n) is a valid multisample level. Bit 0 is always set. std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. }; @@ -593,6 +621,14 @@ struct RenderPassInfo { const char *tag; }; +const int ALL_LAYERS = -1; + +enum class TextureBindFlags { + NONE = 0, + VULKAN_BIND_ARRAY = 1, +}; +ENUM_CLASS_BITOPS(TextureBindFlags); + class DrawContext { public: virtual ~DrawContext(); @@ -654,11 +690,11 @@ public: // These functions should be self explanatory. // Binding a zero render target means binding the backbuffer. + // If an fbo has two layers, we bind for stereo rendering ALWAYS. There's no rendering to one layer anymore. virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) = 0; - virtual Framebuffer *GetCurrentRenderTarget() = 0; // binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2). - virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) = 0; + virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) = 0; // Framebuffer fetch / input attachment support, needs to be explicit in Vulkan. virtual void BindCurrentFramebufferForColorInput() {} @@ -683,7 +719,7 @@ public: virtual void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) = 0; virtual void BindSamplerStates(int start, int count, SamplerState **state) = 0; - virtual void BindTextures(int start, int count, Texture **textures) = 0; + virtual void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags = TextureBindFlags::NONE) = 0; virtual void BindVertexBuffers(int start, int count, Buffer **buffers, const int *offsets) = 0; virtual void BindIndexBuffer(Buffer *indexBuffer, int offset) = 0; @@ -706,7 +742,7 @@ public: // Clear state cached within thin3d. Must be called after directly calling API functions. // Note that framebuffer state (which framebuffer is bounds) may not be cached. // Must not actually perform any API calls itself since this can be called when no framebuffer is bound for rendering. - virtual void InvalidateCachedState() = 0; + virtual void Invalidate(InvalidationFlags flags) = 0; virtual void BindPipeline(Pipeline *pipeline) = 0; @@ -740,7 +776,9 @@ public: // This is called when we launch a new game, so any collected internal stats in the backends don't carry over. virtual void ResetStats() {} - virtual int GetCurrentStepId() const = 0; + // Used by the DrawEngines to know when they have to re-apply some state. + // Not very elegant, but more elegant than the old passId hack. + virtual void SetInvalidationCallback(InvalidationCallback callback) = 0; protected: ShaderModule *vsPresets_[VS_MAX_PRESET]; diff --git a/Common/Input/InputState.h b/Common/Input/InputState.h index faa6416e30..f5d43e209d 100644 --- a/Common/Input/InputState.h +++ b/Common/Input/InputState.h @@ -33,6 +33,7 @@ enum { DEVICE_ID_ACCELEROMETER = 30, DEVICE_ID_XR_CONTROLLER_LEFT = 40, DEVICE_ID_XR_CONTROLLER_RIGHT = 41, + DEVICE_ID_TOUCH = 42, }; //number of contiguous generic joypad IDs diff --git a/Common/Input/KeyCodes.h b/Common/Input/KeyCodes.h index f00dbe8091..15f42c07c1 100644 --- a/Common/Input/KeyCodes.h +++ b/Common/Input/KeyCodes.h @@ -261,7 +261,14 @@ typedef enum _keycode_t { NKCODE_EXT_MOUSEBUTTON_4 = 1006, NKCODE_EXT_MOUSEBUTTON_5 = 1007, NKCODE_EXT_MOUSEWHEEL_UP = 1008, - NKCODE_EXT_MOUSEWHEEL_DOWN = 1009 + NKCODE_EXT_MOUSEWHEEL_DOWN = 1009, + + // Virtual reality controller motion + NKCODE_EXT_MOTION_UP = 1101, + NKCODE_EXT_MOTION_DOWN = 1102, + NKCODE_EXT_MOTION_LEFT = 1103, + NKCODE_EXT_MOTION_RIGHT = 1104, + NKCODE_EXT_MOTION_FORWARD = 1105, } keycode_t; enum AndroidJoystickAxis { diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index cdcb224667..13084098a4 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -56,7 +56,7 @@ void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char if (instance) { instance->Log(level, type, file, line, fmt, args); } else { - // Fall back to printf if we're before the log manager has been initialized. + // Fall back to printf or direct android logger with a small buffer if the log manager hasn't been initialized yet. #if PPSSPP_PLATFORM(ANDROID) char temp[512]; vsnprintf(temp, sizeof(temp), fmt, args); @@ -200,7 +200,7 @@ void LogManager::SaveConfig(Section *section) { } } -void LogManager::LoadConfig(Section *section, bool debugDefaults) { +void LogManager::LoadConfig(const Section *section, bool debugDefaults) { for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) { bool enabled = false; int level = 0; diff --git a/Common/LogManager.h b/Common/LogManager.h index 65423b6121..3ee1347f42 100644 --- a/Common/LogManager.h +++ b/Common/LogManager.h @@ -55,7 +55,7 @@ public: FileLogListener(const char *filename); ~FileLogListener(); - void Log(const LogMessage &msg); + void Log(const LogMessage &msg) override; bool IsValid() { if (!fp_) return false; else return true; } bool IsEnabled() const { return m_enable; } @@ -71,13 +71,12 @@ private: class OutputDebugStringLogListener : public LogListener { public: - void Log(const LogMessage &msg); + void Log(const LogMessage &msg) override; }; class RingbufferLogListener : public LogListener { public: - RingbufferLogListener() : curMessage_(0), count_(0), enabled_(false) {} - void Log(const LogMessage &msg); + void Log(const LogMessage &msg) override; bool IsEnabled() const { return enabled_; } void SetEnabled(bool enable) { enabled_ = enable; } @@ -89,9 +88,9 @@ public: private: enum { MAX_LOGS = 128 }; LogMessage messages_[MAX_LOGS]; - int curMessage_; - int count_; - bool enabled_; + int curMessage_ = 0; + int count_ = 0; + bool enabled_ = false; }; // TODO: A simple buffered log that can be used to display the log in-window @@ -184,5 +183,5 @@ public: void ChangeFileLog(const char *filename); void SaveConfig(Section *section); - void LoadConfig(Section *section, bool debugDefaults); + void LoadConfig(const Section *section, bool debugDefaults); }; diff --git a/Common/Math/expression_parser.cpp b/Common/Math/expression_parser.cpp index 970c9c4a20..b591845bce 100644 --- a/Common/Math/expression_parser.cpp +++ b/Common/Math/expression_parser.cpp @@ -59,45 +59,54 @@ const ExpressionOpcode ExpressionOpcodes[] = { { "", 0, 0, 0, false } // EXOP_NONE }; -bool parseNumber(char* str, int defaultrad, int len, uint32_t& result) -{ +static int radixFromZeroPrefix(char c) { + switch (tolower(c)) { + case 'b': return 2; + case 'o': return 8; + case 'x': return 16; + // Inventing a prefix since we default to hex. + case 'd': return 10; + } + + return -1; +} + +static int radixFromSuffix(char c, int defaultrad) { + switch (tolower(c)) { + case 'o': return 8; + case 'h': return 16; + case 'i': return 10; + case 'u': return 10; + case 'b': return defaultrad == 16 ? -1 : 2; + } + + return -1; +} + +bool parseNumber(char *str, int defaultrad, int len, uint32_t &result) { int val = 0; int r = 0; - if (len == 0) len = (int) strlen(str); + if (len == 0) + len = (int)strlen(str); - if (str[0] == '0' && tolower(str[1]) == 'x') - { - r = 16; - str+=2; - len-=2; - } else if (str[0] == '$') - { + if (str[0] == '0' && radixFromZeroPrefix(str[1]) != -1) { + r = radixFromZeroPrefix(str[1]); + str += 2; + len -= 2; + } else if (str[0] == '$') { r = 16; str++; len--; - } else if (str[0] == '0' && tolower(str[1]) == 'o') - { - r = 8; - str+=2; - len-=2; - } else { - if (!(str[0] >= '0' && str[0] <= '9')) return false; - - if (tolower(str[len-1]) == 'b' && defaultrad != 16) - { - r = 2; - len--; - } else if (tolower(str[len-1]) == 'o') - { - r = 8; - len--; - } else if (tolower(str[len-1]) == 'h') - { - r = 16; + } else if (str[0] >= '0' && str[0] <= '9') { + int suffix = radixFromSuffix(str[len - 1], defaultrad); + if (suffix != -1) { + r = suffix; len--; } else { r = defaultrad; } + } else { + return false; } switch (r) @@ -397,8 +406,8 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, size_t num = 0; uint32_t opcode; std::vector valueStack; - unsigned int arg[5]; - float fArg[5]; + unsigned int arg[5]{}; + float fArg[5]{}; bool useFloat = false; while (num < exp.size()) diff --git a/Common/Math/expression_parser.h b/Common/Math/expression_parser.h index 3d39340a42..55de0a234a 100644 --- a/Common/Math/expression_parser.h +++ b/Common/Math/expression_parser.h @@ -15,6 +15,7 @@ enum ExpressionType class IExpressionFunctions { public: + virtual ~IExpressionFunctions() {} virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0; virtual bool parseSymbol(char* str, uint32_t& symbolValue) = 0; virtual uint32_t getReferenceValue(uint32_t referenceIndex) = 0; diff --git a/Common/Net/HTTPClient.cpp b/Common/Net/HTTPClient.cpp index fec31dabb8..bac18da12d 100644 --- a/Common/Net/HTTPClient.cpp +++ b/Common/Net/HTTPClient.cpp @@ -224,7 +224,7 @@ void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength, float *prog inbuffer->TakeLineCRLF(&line); if (!line.size()) return; - unsigned int chunkSize; + unsigned int chunkSize = 0; sscanf(line.c_str(), "%x", &chunkSize); if (chunkSize) { std::string data; diff --git a/Common/Net/URL.h b/Common/Net/URL.h index 7fcaa0c455..e7f33e6d8a 100644 --- a/Common/Net/URL.h +++ b/Common/Net/URL.h @@ -15,6 +15,8 @@ struct UrlEncoder { + virtual ~UrlEncoder() {} + UrlEncoder() : paramCount(0) { data.reserve(256); @@ -129,8 +131,7 @@ struct MultipartFormDataEncoder : UrlEncoder boundary = temp; } - virtual void Add(const std::string &key, const std::string &value) - { + void Add(const std::string &key, const std::string &value) override { Add(key, value, "", ""); } @@ -158,13 +159,11 @@ struct MultipartFormDataEncoder : UrlEncoder Add(key, std::string((const char *)&value[0], value.size()), filename, mimeType); } - virtual void Finish() - { + void Finish() override { data += "--" + boundary + "--"; } - virtual std::string GetMimeType() const - { + std::string GetMimeType() const override { return "multipart/form-data; boundary=\"" + boundary + "\""; } diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 9b09e7675b..7a50f2844a 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -130,7 +130,7 @@ void DrawBuffer::RectOutline(float x, float y, float w, float h, uint32_t color, vLine(x + w, y, y + h + pixel_in_dps_y, color); } -void DrawBuffer::MultiVGradient(float x, float y, float w, float h, GradientStop *stops, int numStops) { +void DrawBuffer::MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops) { for (int i = 0; i < numStops - 1; i++) { float t0 = stops[i].t, t1 = stops[i+1].t; uint32_t c0 = stops[i].color, c1 = stops[i+1].color; @@ -285,7 +285,9 @@ void DrawBuffer::DrawImageRotated(ImageID atlas_image, float x, float y, float s {u1, image->v2}, }; for (int i = 0; i < 6; i++) { - rot(v[i], angle, x, y); + if (angle != 0.0f) { + rot(v[i], angle, x, y); + } V(v[i][0], v[i][1], 0, color, uv[i][0], uv[i][1]); } } diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index 4a29893c15..8c6262c7c7 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -88,7 +88,7 @@ public: RectVGradient(x, y, w, h, colorTop, darkenColor(colorTop)); } - void MultiVGradient(float x, float y, float w, float h, GradientStop *stops, int numStops); + void MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops); void RectCenter(float x, float y, float w, float h, uint32_t color) { Rect(x - w/2, y - h/2, w, h, color); diff --git a/UI/TextureUtil.cpp b/Common/Render/ManagedTexture.cpp similarity index 83% rename from UI/TextureUtil.cpp rename to Common/Render/ManagedTexture.cpp index 80dfb59e1a..771d4f8a92 100644 --- a/UI/TextureUtil.cpp +++ b/Common/Render/ManagedTexture.cpp @@ -14,8 +14,7 @@ #include "Common/File/VFS/VFS.h" #include "Common/Log.h" #include "Common/TimeUtil.h" -#include "UI/TextureUtil.h" -#include "UI/GameInfoCache.h" +#include "Common/Render/ManagedTexture.h" static Draw::DataFormat ZimToT3DFormat(int zim) { switch (zim) { @@ -217,38 +216,3 @@ std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *dra return std::unique_ptr(); } } - -void GameIconView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - w = textureWidth_; - h = textureHeight_; -} - -void GameIconView::Draw(UIContext &dc) { - using namespace UI; - std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); - - if (!info->icon.texture) { - return; - } - - textureWidth_ = info->icon.texture->Width() * scale_; - textureHeight_ = info->icon.texture->Height() * scale_; - - // Fade icon with the backgrounds. - double loadTime = info->icon.timeLoaded; - auto pic = info->GetBGPic(); - if (pic) { - loadTime = std::max(loadTime, pic->timeLoaded); - } - uint32_t color = whiteAlpha(ease((time_now_d() - loadTime) * 3)); - - // Adjust size so we don't stretch the image vertically or horizontally. - // Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode. - float nw = std::min(bounds_.h * textureWidth_ / textureHeight_, (float)bounds_.w); - - dc.Flush(); - dc.GetDrawContext()->BindTexture(0, info->icon.texture->GetTexture()); - dc.Draw()->Rect(bounds_.x, bounds_.y, nw, bounds_.h, color); - dc.Flush(); - dc.RebindTexture(); -} diff --git a/UI/TextureUtil.h b/Common/Render/ManagedTexture.h similarity index 73% rename from UI/TextureUtil.h rename to Common/Render/ManagedTexture.h index 19d9b40cb0..ed6e9918f6 100644 --- a/UI/TextureUtil.h +++ b/Common/Render/ManagedTexture.h @@ -43,18 +43,3 @@ private: std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips); std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips, const char *name); -class GameIconView : public UI::InertView { -public: - GameIconView(const Path &gamePath, float scale, UI::LayoutParams *layoutParams = 0) - : InertView(layoutParams), gamePath_(gamePath), scale_(scale) {} - - void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; - void Draw(UIContext &dc) override; - std::string DescribeText() const override { return ""; } - -private: - Path gamePath_; - float scale_ = 1.0f; - int textureWidth_ = 0; - int textureHeight_ = 0; -}; diff --git a/Common/Render/Text/draw_text_win.cpp b/Common/Render/Text/draw_text_win.cpp index d5af5af762..6cd9885fee 100644 --- a/Common/Render/Text/draw_text_win.cpp +++ b/Common/Render/Text/draw_text_win.cpp @@ -69,6 +69,7 @@ TextDrawerWin32::TextDrawerWin32(Draw::DrawContext *draw) : TextDrawer(draw), ct bmi.bmiHeader.biBitCount = 32; ctx_->hbmBitmap = CreateDIBSection(ctx_->hDC, &bmi, DIB_RGB_COLORS, (VOID**)&ctx_->pBitmapBits, NULL, 0); + _assert_(ctx_->hbmBitmap != nullptr); SetMapMode(ctx_->hDC, MM_TEXT); SelectObject(ctx_->hDC, ctx_->hbmBitmap); diff --git a/Common/RiscVEmitter.cpp b/Common/RiscVEmitter.cpp index 3f0d47499b..6849acbd19 100644 --- a/Common/RiscVEmitter.cpp +++ b/Common/RiscVEmitter.cpp @@ -615,7 +615,7 @@ const u8 *RiscVEmitter::AlignCode16() { const u8 *RiscVEmitter::AlignCodePage() { int page_size = GetMemoryProtectPageSize(); - int c = int((u64)code_ & (page_size - 1)); + int c = int((intptr_t)code_ & ((intptr_t)page_size - 1)); if (c) ReserveCodeSpace(page_size - c); return code_; @@ -747,7 +747,7 @@ void RiscVEmitter::SetRegToImmediate(RiscVReg rd, uint64_t value, RiscVReg temp) if (SignReduce64(v, 32) == v || force) { int32_t lower = (int32_t)SignReduce64(svalue, 12); int32_t upper = ((v - lower) >> 12) << 12; - _assert_msg_(force || upper + lower == v, "Upper + ADDI immediate math mistake?"); + _assert_msg_(force || (int64_t)upper + lower == v, "Upper + ADDI immediate math mistake?"); // Should be fused on some processors. (this->*upperOp)(rd, upper); diff --git a/Common/RiscVEmitter.h b/Common/RiscVEmitter.h index f2e512a32c..e1b8266a56 100644 --- a/Common/RiscVEmitter.h +++ b/Common/RiscVEmitter.h @@ -113,7 +113,7 @@ struct FixupBranch { ~FixupBranch(); const u8 *ptr = nullptr; - FixupBranchType type; + FixupBranchType type = FixupBranchType::B; }; class RiscVEmitter { diff --git a/Common/Serialize/SerializeFuncs.h b/Common/Serialize/SerializeFuncs.h index 3080749fa3..c2919de799 100644 --- a/Common/Serialize/SerializeFuncs.h +++ b/Common/Serialize/SerializeFuncs.h @@ -33,11 +33,7 @@ void Do(PointerWrap &p, tm &t); // This makes it a compile error if you forget to define DoState() on non-POD. // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... -#ifdef _MSC_VER -template::value, bool isPointer = std::is_pointer::value> -#else -template::value> -#endif +template::value && std::is_trivial::value, bool isPointer = std::is_pointer::value> struct DoHelper_ { static void DoArray(PointerWrap &p, T *x, int count) { for (int i = 0; i < count; ++i) @@ -89,7 +85,8 @@ template void DoVector(PointerWrap &p, std::vector &x, T &default_val) { u32 vec_size = (u32)x.size(); Do(p, vec_size); - x.resize(vec_size, default_val); + if (vec_size != x.size()) + x.resize(vec_size, default_val); if (vec_size > 0) DoArray(p, &x[0], vec_size); } diff --git a/Common/Serialize/SerializeMap.h b/Common/Serialize/SerializeMap.h index 9190f5067e..4e5619bdbe 100644 --- a/Common/Serialize/SerializeMap.h +++ b/Common/Serialize/SerializeMap.h @@ -38,8 +38,8 @@ void DoMap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { x[first] = second; --number; } + break; } - break; case PointerWrap::MODE_WRITE: case PointerWrap::MODE_MEASURE: case PointerWrap::MODE_VERIFY: @@ -52,8 +52,10 @@ void DoMap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { --number; ++itr; } + break; } - break; + case PointerWrap::MODE_NOOP: + break; } } @@ -109,8 +111,8 @@ void DoMultimap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { x.insert(std::make_pair(first, second)); --number; } + break; } - break; case PointerWrap::MODE_WRITE: case PointerWrap::MODE_MEASURE: case PointerWrap::MODE_VERIFY: @@ -122,8 +124,10 @@ void DoMultimap(PointerWrap &p, M &x, typename M::mapped_type &default_val) { --number; ++itr; } + break; } - break; + case PointerWrap::MODE_NOOP: + break; } } diff --git a/Common/Serialize/SerializeSet.h b/Common/Serialize/SerializeSet.h index 7e22f21e56..642b0dc6bb 100644 --- a/Common/Serialize/SerializeSet.h +++ b/Common/Serialize/SerializeSet.h @@ -46,9 +46,8 @@ void DoSet(PointerWrap &p, std::set &x) { Do(p, *itr++); } break; - - default: - ERROR_LOG(SAVESTATE, "Savestate error: invalid mode %d.", p.mode); + case PointerWrap::MODE_NOOP: + break; } } diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index 6b36fb2167..71f5168c3b 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -33,8 +33,27 @@ enum class SerializeCompressType { static constexpr SerializeCompressType SAVE_TYPE = SerializeCompressType::ZSTD; -PointerWrapSection PointerWrap::Section(const char *title, int ver) { - return Section(title, ver, ver); +void PointerWrap::RewindForWrite(u8 *writePtr) { + _assert_(mode == MODE_MEASURE); + // Switch to writing mode, save the size for later checking and start again. + measuredSize_ = Offset(); + mode = MODE_WRITE; + *ptr = writePtr; + ptrStart_ = writePtr; +} + +bool PointerWrap::CheckAfterWrite() { + _assert_(error != ERROR_NONE || mode == MODE_WRITE); + size_t offset = Offset(); + if (measuredSize_ != 0 && offset != measuredSize_) { + WARN_LOG(SAVESTATE, "CheckAfterWrite: Size mismatch! %d but expected %d", (int)offset, (int)measuredSize_); + return false; + } + if (!checkpoints_.empty() && curCheckpoint_ != checkpoints_.size()) { + WARN_LOG(SAVESTATE, "Checkpoint count mismatch!"); + return false; + } + return true; } PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) { @@ -44,6 +63,32 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) // This is strncpy because we rely on its weird non-null-terminating zero-filling truncation behaviour. // Can't replace it with the more sensible truncate_cpy because that would break savestates. strncpy(marker, title, sizeof(marker)); + + // Compare the measure and write passes. Sanity check to catch bugs, doesn't do anything for output. + size_t offset = Offset(); + if (mode == MODE_MEASURE) { + checkpoints_.emplace_back(marker, offset); + } else if (mode == MODE_WRITE) { + if (!checkpoints_.empty()) { + if (checkpoints_.size() <= curCheckpoint_) { + WARN_LOG(SAVESTATE, "Write: Not enough checkpoints from measure pass (%d). cur section: %s", (int)checkpoints_.size(), title); + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + if (!checkpoints_[curCheckpoint_].Matches(marker, offset)) { + WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s but expected %s, offset %d but expected %d", title, marker, (int)offset, (int)checkpoints_[curCheckpoint_].offset); + if (curCheckpoint_ > 1) { + WARN_LOG(SAVESTATE, "Previous checkpoint: %s (%d)", checkpoints_[curCheckpoint_ - 1].title, (int)checkpoints_[curCheckpoint_ - 1].offset); + } + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + } else { + WARN_LOG(SAVESTATE, "Writing savestate without checkpoints. This is OK but should be fixed."); + } + curCheckpoint_++; + } + if (!ExpectVoid(marker, sizeof(marker))) { // Might be before we added name markers for safety. if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) { @@ -60,8 +105,10 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) if (!firstBadSectionTitle_) { firstBadSectionTitle_ = title; } - WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); - SetError(ERROR_FAILURE); + if (mode != MODE_NOOP) { + WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); + SetError(ERROR_FAILURE); + } return PointerWrapSection(*this, -1, title); } return PointerWrapSection(*this, foundVersion, title); @@ -72,8 +119,9 @@ void PointerWrap::SetError(Error error_) { error = error_; } if (error > ERROR_WARNING) { - // For the rest of this run, just measure. - mode = PointerWrap::MODE_MEASURE; + // For the rest of this run, do nothing, to avoid running off the end of memory or something, + // and also not logspam like MEASURE will do in an error case. + mode = PointerWrap::MODE_NOOP; } } @@ -123,6 +171,7 @@ void Do(PointerWrap &p, std::string &x) { case PointerWrap::MODE_READ: x = (char*)*p.ptr; break; case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_NOOP: break; case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(!strcmp(x.c_str(), (char*)*p.ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char *)*p.ptr, p.ptr); break; } (*p.ptr) += stringLen; @@ -150,6 +199,7 @@ void Do(PointerWrap &p, std::wstring &x) { case PointerWrap::MODE_READ: x = read(); break; case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_NOOP: break; case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(x == read(), "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), read().c_str(), p.ptr); break; } (*p.ptr) += stringLen; @@ -177,6 +227,7 @@ void Do(PointerWrap &p, std::u16string &x) { case PointerWrap::MODE_READ: x = read(); break; case PointerWrap::MODE_WRITE: memcpy(*p.ptr, x.c_str(), stringLen); break; case PointerWrap::MODE_MEASURE: break; + case PointerWrap::MODE_NOOP: break; case PointerWrap::MODE_VERIFY: _dbg_assert_msg_(x == read(), "Savestate verification failure: (at %p).\n", p.ptr); break; } (*p.ptr) += stringLen; diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h index cdf8bd4f06..5169e4a120 100644 --- a/Common/Serialize/Serializer.h +++ b/Common/Serialize/Serializer.h @@ -30,6 +30,7 @@ // - Serialization code for anything complex has to be manually written. #include +#include #include #include @@ -52,8 +53,7 @@ class PointerWrap; class PointerWrapSection { public: - PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { - } + PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {} ~PointerWrapSection(); bool operator == (const int &v) const { return ver_ == v; } @@ -73,15 +73,32 @@ private: const char *title_; }; +// For measure vs write detailed verification +struct SerializeCheckpoint { + char title[17]; // 16-byte section header, plus a zero terminator for debug printing. + size_t offset; + + SerializeCheckpoint(char _title[16], size_t off) { + memcpy(title, _title, 16); + title[16] = 0; + offset = off; + } + + bool Matches(const char *_title, size_t off) const { + return memcmp(title, _title, 16) == 0 && off == offset; + } +}; + // Wrapper class class PointerWrap { public: enum Mode { MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + MODE_NOOP, // don't do anything. Useful to cleanly doing stuff once we've hit an error. }; enum Error { @@ -94,19 +111,26 @@ public: Mode mode; Error error = ERROR_NONE; - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {} + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), ptrStart_(*ptr), mode(mode_) { + if (mode == MODE_MEASURE) { + checkpoints_.reserve(750); + } + } - PointerWrapSection Section(const char *title, int ver); + void RewindForWrite(u8 *writePtr); + bool CheckAfterWrite(); // The returned object can be compared against the version that was loaded. // This can be used to support versions as old as minVer. // Version = 0 means the section was not found. PointerWrapSection Section(const char *title, int minVer, int ver); + PointerWrapSection Section(const char *title, int ver) { + return Section(title, ver, ver); + } - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} + void SetMode(Mode mode_) { mode = mode_; } + Mode GetMode() const { return mode; } + u8 **GetPPtr() { return ptr; } void SetError(Error error_); const char *GetBadSectionTitle() const { @@ -119,8 +143,14 @@ public: void DoMarker(const char *prevName, u32 arbitraryNumber = 0x42); + size_t Offset() const { return *ptr - ptrStart_; } + private: const char *firstBadSectionTitle_ = nullptr; + u8 *ptrStart_; + std::vector checkpoints_; + size_t curCheckpoint_ = 0; + size_t measuredSize_ = 0; }; class CChunkFileReader @@ -152,7 +182,7 @@ public: template static size_t MeasurePtr(T &_class) { - u8 *ptr = 0; + u8 *ptr = nullptr; PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); _class.DoState(p); return (size_t)ptr; @@ -166,13 +196,39 @@ public: PointerWrap p(&ptr, PointerWrap::MODE_WRITE); _class.DoState(p); - if (p.error != p.ERROR_FAILURE && (expected_end == ptr || expected_size == 0)) { + if (p.error != PointerWrap::ERROR_FAILURE && (expected_end == ptr || expected_size == 0)) { return ERROR_NONE; } else { return ERROR_BROKEN_STATE; } } + template + static Error MeasureAndSavePtr(T &_class, u8 **saved, size_t *savedSize) + { + u8 *ptr = nullptr; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + _assert_(p.error == PointerWrap::ERROR_NONE); + + size_t measuredSize = p.Offset(); + u8 *data = (u8 *)malloc(measuredSize); + if (!data) + return ERROR_BAD_ALLOC; + + p.RewindForWrite(data); + _class.DoState(p); + + if (p.CheckAfterWrite()) { + *saved = data; + *savedSize = measuredSize; + return ERROR_NONE; + } else { + free(data); + return ERROR_BROKEN_STATE; + } + } + // Load file template template static Error Load(const Path &filename, std::string *gitVersion, T& _class, std::string *failureReason) @@ -197,19 +253,16 @@ public: template static Error Save(const Path &filename, const std::string &title, const char *gitVersion, T& _class) { - // Get data - size_t const sz = MeasurePtr(_class); - u8 *buffer = (u8 *)malloc(sz); - if (!buffer) - return ERROR_BAD_ALLOC; - Error error = SavePtr(buffer, _class, sz); + u8 *buffer; + size_t sz; + Error error = MeasureAndSavePtr(_class, &buffer, &sz); - // SaveFile takes ownership of buffer + // SaveFile takes ownership of buffer (malloc/free) if (error == ERROR_NONE) error = SaveFile(filename, title, gitVersion, buffer, sz); return error; } - + template static Error Verify(T& _class) { diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index 3a9e29c61a..3115e1f03c 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -286,6 +286,25 @@ void SplitString(const std::string& str, const char delim, std::vector& output) { size_t next = 0; @@ -294,7 +313,7 @@ void GetQuotedStrings(const std::string& str, std::vector& output) if (str[pos] == '\"' || str[pos] == '\'') { if (even) { //quoted text - output.emplace_back(str.substr(next, pos - next)); + output.emplace_back(ApplyHtmlEscapes(str.substr(next, pos - next))); even = 0; } else { //non quoted text diff --git a/Common/Thread/Channel.h b/Common/Thread/Channel.h index b6b23fdebe..82772bb6f4 100644 --- a/Common/Thread/Channel.h +++ b/Common/Thread/Channel.h @@ -20,10 +20,11 @@ struct Mailbox { std::mutex mutex_; std::condition_variable condvar_; T data_{}; + bool dataReceived_ = false; T Wait() { std::unique_lock lock(mutex_); - while (!data_) { + while (!dataReceived_) { condvar_.wait(lock); } return data_; @@ -31,7 +32,7 @@ struct Mailbox { bool Poll(T *data) { std::unique_lock lock(mutex_); - if (data_) { + if (dataReceived_) { *data = data_; return true; } else { @@ -41,8 +42,9 @@ struct Mailbox { bool Send(T data) { std::unique_lock lock(mutex_); - if (!data_) { + if (!dataReceived_) { data_ = data; + dataReceived_ = true; condvar_.notify_all(); return true; } else { diff --git a/Common/Thread/Promise.h b/Common/Thread/Promise.h index 4145b4b6c1..96c36f9605 100644 --- a/Common/Thread/Promise.h +++ b/Common/Thread/Promise.h @@ -107,7 +107,7 @@ public: } } - // For outside injection of data, when not using Spawn + // For outside injection of data, when not using Spawn. void Post(T data) { rx_->Send(data); } diff --git a/Common/Thread/ThreadManager.cpp b/Common/Thread/ThreadManager.cpp index 5fca697635..0414ee5e79 100644 --- a/Common/Thread/ThreadManager.cpp +++ b/Common/Thread/ThreadManager.cpp @@ -113,7 +113,7 @@ bool ThreadManager::TeardownTask(Task *task, bool enqueue) { if (task->Type() == TaskType::CPU_COMPUTE) { global_->compute_queue.push_back(task); global_->compute_queue_size++; - } else if (task->Type() == TaskType::CPU_COMPUTE) { + } else if (task->Type() == TaskType::IO_BLOCKING) { global_->io_queue.push_back(task); global_->io_queue_size++; } else { @@ -125,7 +125,12 @@ bool ThreadManager::TeardownTask(Task *task, bool enqueue) { static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread) { char threadName[16]; - snprintf(threadName, sizeof(threadName), "PoolWorker %d", thread->index); + if (thread->type == TaskType::CPU_COMPUTE) { + snprintf(threadName, sizeof(threadName), "PoolWorker %d", thread->index); + } else { + _assert_(thread->type == TaskType::IO_BLOCKING); + snprintf(threadName, sizeof(threadName), "PoolWorkerIO %d", thread->index); + } SetCurrentThreadName(threadName); const bool isCompute = thread->type == TaskType::CPU_COMPUTE; @@ -199,8 +204,8 @@ void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) { thread->cancelled.store(false); thread->private_single.store(nullptr); thread->type = i < numComputeThreads_ ? TaskType::CPU_COMPUTE : TaskType::IO_BLOCKING; - thread->thread = std::thread(&WorkerThreadFunc, global_, thread); thread->index = i; + thread->thread = std::thread(&WorkerThreadFunc, global_, thread); global_->threads_.push_back(thread); } } diff --git a/Common/Thread/ThreadManager.h b/Common/Thread/ThreadManager.h index 5147ad21cc..bd71d8c775 100644 --- a/Common/Thread/ThreadManager.h +++ b/Common/Thread/ThreadManager.h @@ -4,7 +4,7 @@ // The new threadpool. -// To help future smart scheduling. +// To help smart scheduling. enum class TaskType { CPU_COMPUTE, IO_BLOCKING, diff --git a/Common/Thunk.cpp b/Common/Thunk.cpp index 6248d087a0..581ce94b94 100644 --- a/Common/Thunk.cpp +++ b/Common/Thunk.cpp @@ -43,7 +43,7 @@ void ThunkManager::Init() #endif AllocCodeSpace(THUNK_ARENA_SIZE); - BeginWrite(); + BeginWrite(512); save_regs = GetCodePtr(); #if PPSSPP_ARCH(AMD64) for (int i = 2; i < ABI_GetNumXMMRegs(); i++) @@ -151,7 +151,7 @@ const void *ThunkManager::ProtectFunction(const void *function, int num_params) _assert_msg_(region != nullptr, "Can't protect functions before the emu is started."); - BeginWrite(); + BeginWrite(128); const u8 *call_point = GetCodePtr(); Enter(this, true); diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp index ad00e1e9a7..ad07fbd18c 100644 --- a/Common/TimeUtil.cpp +++ b/Common/TimeUtil.cpp @@ -21,8 +21,6 @@ // TODO: https://github.com/floooh/sokol/blob/9a6237fcdf213e6da48e4f9201f144bcb2dcb46f/sokol_time.h#L229-L248 -static double curtime = 0; - #ifdef _WIN32 static LARGE_INTEGER frequency; @@ -33,7 +31,6 @@ double time_now_d() { if (frequency.QuadPart == 0) { QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&startTime); - curtime = 0.0; frequencyMult = 1.0 / static_cast(frequency.QuadPart); } LARGE_INTEGER time; diff --git a/Common/UI/AsyncImageFileView.cpp b/Common/UI/AsyncImageFileView.cpp new file mode 100644 index 0000000000..925d1c9337 --- /dev/null +++ b/Common/UI/AsyncImageFileView.cpp @@ -0,0 +1,113 @@ +#include "Common/UI/View.h" +#include "Common/UI/AsyncImageFileView.h" +#include "Common/UI/Context.h" +#include "Common/Render/DrawBuffer.h" + +AsyncImageFileView::AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams) + : UI::Clickable(layoutParams), canFocus_(true), filename_(filename), color_(0xFFFFFFFF), sizeMode_(sizeMode), textureFailed_(false), fixedSizeW_(0.0f), fixedSizeH_(0.0f) {} + +AsyncImageFileView::~AsyncImageFileView() {} + +static float DesiredSize(float sz, float contentSize, UI::MeasureSpec spec) { + float measured; + UI::MeasureBySpec(sz, contentSize, spec, &measured); + return measured; +} + +void AsyncImageFileView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const { + if (texture_ && texture_->GetTexture()) { + float texw = (float)texture_->Width(); + float texh = (float)texture_->Height(); + float desiredW = DesiredSize(layoutParams_->width, w, horiz); + float desiredH = DesiredSize(layoutParams_->height, h, vert); + switch (sizeMode_) { + case UI::IS_FIXED: + w = fixedSizeW_; + h = fixedSizeH_; + break; + case UI::IS_KEEP_ASPECT: + w = texw; + h = texh; + if (desiredW != w || desiredH != h) { + float aspect = w / h; + // We need the other dimension based on the desired scale to find the best aspect. + float desiredWOther = DesiredSize(layoutParams_->height, h * (desiredW / w), vert); + float desiredHOther = DesiredSize(layoutParams_->width, w * (desiredH / h), horiz); + + float diffW = fabsf(aspect - desiredW / desiredWOther); + float diffH = fabsf(aspect - desiredH / desiredHOther); + if (diffW < diffH) { + w = desiredW; + h = desiredWOther; + } else { + w = desiredHOther; + h = desiredH; + } + } + break; + case UI::IS_DEFAULT: + default: + w = texw; + h = texh; + break; + } + } else { + w = 16; + h = 16; + } +} + +void AsyncImageFileView::SetFilename(const Path &filename) { + if (filename_ != filename) { + textureFailed_ = false; + filename_ = filename; + texture_.reset(nullptr); + } +} + +void AsyncImageFileView::DeviceLost() { + if (texture_.get()) + texture_->DeviceLost(); +} + +void AsyncImageFileView::DeviceRestored(Draw::DrawContext *draw) { + if (texture_.get()) + texture_->DeviceRestored(draw); +} + +void AsyncImageFileView::Draw(UIContext &dc) { + using namespace Draw; + if (!texture_ && !textureFailed_ && !filename_.empty()) { + texture_ = CreateTextureFromFile(dc.GetDrawContext(), filename_.c_str(), DETECT, true); + if (!texture_.get()) + textureFailed_ = true; + } + + if (HasFocus()) { + dc.FillRect(dc.theme->itemFocusedStyle.background, bounds_.Expand(3)); + } + + // TODO: involve sizemode + if (texture_ && texture_->GetTexture()) { + dc.Flush(); + dc.GetDrawContext()->BindTexture(0, texture_->GetTexture()); + dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); + dc.Flush(); + dc.RebindTexture(); + if (!text_.empty()) { + dc.DrawText(text_.c_str(), bounds_.centerX() + 1, bounds_.centerY() + 1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + } + } else { + if (!filename_.empty()) { + // draw a black rectangle to represent the missing screenshot. + dc.FillRect(UI::Drawable(0xFF000000), GetBounds()); + } else { + // draw a dark gray rectangle to represent no save state. + dc.FillRect(UI::Drawable(0x50202020), GetBounds()); + } + if (!text_.empty()) { + dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + } + } +} diff --git a/Common/UI/AsyncImageFileView.h b/Common/UI/AsyncImageFileView.h new file mode 100644 index 0000000000..5acaca30a5 --- /dev/null +++ b/Common/UI/AsyncImageFileView.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Common/UI/View.h" +#include "Common/Render/ManagedTexture.h" +#include "Common/File/Path.h" + +class UIContext; + +// AsyncImageFileView loads a texture from a file, and reloads it as necessary. +// TODO: Actually make async, doh. +class AsyncImageFileView : public UI::Clickable { +public: + AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams = 0); + ~AsyncImageFileView(); + + void GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const override; + void Draw(UIContext &dc) override; + std::string DescribeText() const override { return text_; } + + void DeviceLost() override; + void DeviceRestored(Draw::DrawContext *draw) override; + + void SetFilename(const Path &filename); + void SetColor(uint32_t color) { color_ = color; } + void SetOverlayText(std::string text) { text_ = text; } + void SetFixedSize(float fixW, float fixH) { fixedSizeW_ = fixW; fixedSizeH_ = fixH; } + void SetCanBeFocused(bool can) { canFocus_ = can; } + + bool CanBeFocused() const override { return canFocus_; } + + const Path &GetFilename() const { return filename_; } + +private: + bool canFocus_; + Path filename_; + std::string text_; + uint32_t color_; + UI::ImageSizeMode sizeMode_; + + std::unique_ptr texture_; + bool textureFailed_; + float fixedSizeW_; + float fixedSizeH_; +}; diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index 21c687bd2b..40bc95c824 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -10,9 +10,9 @@ #include "Common/UI/Context.h" #include "Common/Render/DrawBuffer.h" #include "Common/Render/Text/draw_text.h" +#include "Common/Render/ManagedTexture.h" #include "Common/Log.h" #include "Common/LogReporting.h" -#include "UI/TextureUtil.h" UIContext::UIContext() { fontStyle_ = new UI::FontStyle(); diff --git a/Common/UI/Context.h b/Common/UI/Context.h index ac26ab0202..b7c6982176 100644 --- a/Common/UI/Context.h +++ b/Common/UI/Context.h @@ -71,7 +71,6 @@ public: DrawBuffer *Draw() const { return uidrawbuffer_; } DrawBuffer *DrawTop() const { return uidrawbufferTop_; } - const UI::Theme *theme; // Utility methods TextDrawer *Text() const { return textDrawer_; } @@ -94,6 +93,9 @@ public: const Bounds &GetBounds() const { return bounds_; } Bounds GetLayoutBounds() const; Draw::DrawContext *GetDrawContext() { return draw_; } + const UI::Theme &GetTheme() const { + return *theme; + } void SetCurZ(float curZ); void PushTransform(const UITransform &transform); @@ -106,6 +108,9 @@ public: screenTag_ = tag; } + // TODO: Move to private. + const UI::Theme *theme; + private: Draw::DrawContext *draw_ = nullptr; Bounds bounds_; diff --git a/Common/UI/Root.cpp b/Common/UI/Root.cpp index b02ae9ee55..ccd1f67352 100644 --- a/Common/UI/Root.cpp +++ b/Common/UI/Root.cpp @@ -33,9 +33,7 @@ std::atomic hasDispatchQueue; std::deque g_dispatchQueue; void EventTriggered(Event *e, EventParams params) { - DispatchQueueItem item; - item.e = e; - item.params = params; + DispatchQueueItem item{ e, params }; std::unique_lock guard(eventMutex_); // Set before adding so we lock and check the added value. diff --git a/Common/UI/UI.h b/Common/UI/UI.h index ccd6b50dbe..4357693d16 100644 --- a/Common/UI/UI.h +++ b/Common/UI/UI.h @@ -43,6 +43,7 @@ extern DrawBuffer ui_draw2d_front; // for things that need to be on top of the r // Implement this interface to style your lists class UIListAdapter { public: + virtual ~UIListAdapter() {} virtual size_t getCount() const = 0; virtual void drawItem(int item, int x, int y, int w, int h, bool active) const = 0; virtual float itemHeight(int itemIndex) const { return 64; } @@ -52,8 +53,8 @@ public: class StringVectorListAdapter : public UIListAdapter { public: StringVectorListAdapter(const std::vector *items) : items_(items) {} - virtual size_t getCount() const { return items_->size(); } - virtual void drawItem(int item, int x, int y, int w, int h, bool active) const; + size_t getCount() const override { return items_->size(); } + void drawItem(int item, int x, int y, int w, int h, bool active) const override; private: const std::vector *items_; diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index ecebae3a81..d1623101d0 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -12,7 +12,6 @@ #include "Common/UI/Root.h" #include "Common/Data/Text/I18n.h" #include "Common/Render/DrawBuffer.h" -#include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/StringUtils.h" @@ -21,12 +20,17 @@ static const bool ClickDebug = false; UIScreen::UIScreen() : Screen() { + lastVertical_ = UseVerticalLayout(); } UIScreen::~UIScreen() { delete root_; } +bool UIScreen::UseVerticalLayout() const { + return dp_yres > dp_xres * 1.1f; +} + void UIScreen::DoRecreateViews() { if (recreateViews_) { std::lock_guard guard(screenManager()->inputLock_); @@ -61,6 +65,12 @@ void UIScreen::DoRecreateViews() { } void UIScreen::update() { + bool vertical = UseVerticalLayout(); + if (vertical != lastVertical_) { + RecreateViews(); + lastVertical_ = vertical; + } + DoRecreateViews(); if (root_) { @@ -89,10 +99,6 @@ void UIScreen::preRender() { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); screenManager()->getUIContext()->BeginFrame(); - if (IsVRBuild()) { - BindVRFramebuffer(); - } - Draw::Viewport viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; @@ -317,10 +323,6 @@ void PopupScreen::TriggerFinish(DialogResult result) { } } -void PopupScreen::resized() { - RecreateViews(); -} - void PopupScreen::CreateViews() { using namespace UI; UIContext &dc = *screenManager()->getUIContext(); @@ -341,7 +343,9 @@ void PopupScreen::CreateViews() { box_->SetDropShadowExpand(std::max(dp_xres, dp_yres)); View *title = new PopupHeader(title_); - box_->Add(title); + if (HasTitleBar()) { + box_->Add(title); + } CreatePopupContents(box_); root_->SetDefaultFocusView(box_); @@ -408,6 +412,39 @@ UI::EventReturn ListPopupScreen::OnListChoice(UI::EventParams &e) { namespace UI { +PopupContextMenuScreen::PopupContextMenuScreen(const ContextMenuItem *items, size_t itemCount, I18NCategory *category, UI::View *sourceView) + : PopupScreen("", "", ""), items_(items), itemCount_(itemCount), category_(category), sourceView_(sourceView) +{ + enabled_.resize(itemCount, true); + SetPopupOrigin(sourceView); +} + +void PopupContextMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { + for (size_t i = 0; i < itemCount_; i++) { + if (items_[i].imageID) { + Choice *choice = new Choice(category_->T(items_[i].text), ImageID(items_[i].imageID)); + parent->Add(choice); + if (enabled_[i]) { + choice->OnClick.Add([=](EventParams &p) { + TriggerFinish(DR_OK); + p.a = (uint32_t)i; + OnChoice.Dispatch(p); + return EVENT_DONE; + }); + } + else { + choice->SetEnabled(false); + } + } + } + + // Hacky: Override the position to look like a popup menu. + AnchorLayoutParams *ap = (AnchorLayoutParams *)parent->GetLayoutParams(); + ap->center = false; + ap->left = sourceView_->GetBounds().x; + ap->top = sourceView_->GetBounds().y2(); +} + std::string ChopTitle(const std::string &title) { size_t pos = title.find('\n'); if (pos != title.npos) { @@ -819,7 +856,7 @@ void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext const std::string valueText = ValueText(); int paddingX = 12; // Assume we want at least 20% of the size for the label, at a minimum. - float availWidth = (horiz.size - paddingX * 2) * 0.8f; + float availWidth = (horiz.size - paddingX * 2) * (text_.empty() ? 1.0f : 0.8f); if (availWidth < 0) { availWidth = 65535.0f; } @@ -831,11 +868,15 @@ void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext valueW += paddingX; // Give the choice itself less space to grow in, so it shrinks if needed. - MeasureSpec horizLabel = horiz; - horizLabel.size -= valueW; + // MeasureSpec horizLabel = horiz; + // horizLabel.size -= valueW; Choice::GetContentDimensionsBySpec(dc, horiz, vert, w, h); w += valueW; + // Fill out anyway if there's space. + if (horiz.type == AT_MOST && w < horiz.size) { + w = horiz.size; + } h = std::max(h, valueH); } @@ -854,20 +895,30 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { dc.SetFontStyle(dc.theme->uiFont); const std::string valueText = ValueText(); - // Assume we want at least 20% of the size for the label, at a minimum. - float availWidth = (bounds_.w - paddingX * 2) * 0.8f; - float scale = CalculateValueScale(dc, valueText, availWidth); - float w, h; - Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); - textPadding_.right = w + paddingX; + // If there is a label, assume we want at least 20% of the size for it, at a minimum. - Choice::Draw(dc); - dc.SetFontScale(scale, scale); - Bounds valueBounds(bounds_.x2() - textPadding_.right, bounds_.y, w, bounds_.h); - dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); - dc.SetFontScale(1.0f, 1.0f); + if (!text_.empty()) { + float availWidth = (bounds_.w - paddingX * 2) * 0.8f; + float scale = CalculateValueScale(dc, valueText, availWidth); + + float w, h; + Bounds availBounds(0, 0, availWidth, bounds_.h); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + textPadding_.right = w + paddingX; + + Choice::Draw(dc); + dc.SetFontScale(scale, scale); + Bounds valueBounds(bounds_.x2() - textPadding_.right, bounds_.y, w, bounds_.h); + dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.SetFontScale(1.0f, 1.0f); + } else { + Choice::Draw(dc); + float scale = CalculateValueScale(dc, valueText, bounds_.w); + dc.SetFontScale(scale, scale); + dc.DrawTextRect(valueText.c_str(), bounds_.Expand(-paddingX, 0.0f), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.SetFontScale(1.0f, 1.0f); + } } float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const { diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 4b113d3001..50a5f1f2d9 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -42,7 +42,8 @@ protected: virtual void CreateViews() = 0; virtual void DrawBackground(UIContext &dc) {} - virtual void RecreateViews() override { recreateViews_ = true; } + void RecreateViews() override { recreateViews_ = true; } + bool UseVerticalLayout() const; UI::ViewGroup *root_ = nullptr; Vec3 translation_ = Vec3(0.0f); @@ -54,6 +55,7 @@ private: void DoRecreateViews(); bool recreateViews_ = true; + bool lastVertical_; }; class UIDialogScreen : public UIScreen { @@ -72,13 +74,12 @@ public: PopupScreen(std::string title, std::string button1 = "", std::string button2 = ""); virtual void CreatePopupContents(UI::ViewGroup *parent) = 0; - virtual void CreateViews() override; - virtual bool isTransparent() const override { return true; } - virtual bool touch(const TouchInput &touch) override; - virtual bool key(const KeyInput &key) override; - virtual void resized() override; + void CreateViews() override; + bool isTransparent() const override { return true; } + bool touch(const TouchInput &touch) override; + bool key(const KeyInput &key) override; - virtual void TriggerFinish(DialogResult result) override; + void TriggerFinish(DialogResult result) override; void SetPopupOrigin(const UI::View *view); void SetPopupOffset(float y); @@ -91,9 +92,10 @@ protected: virtual bool ShowButtons() const { return true; } virtual bool CanComplete(DialogResult result) { return true; } virtual void OnCompleted(DialogResult result) {} + virtual bool HasTitleBar() const { return true; } const std::string &Title() { return title_; } - virtual void update() override; + void update() override; private: UI::ViewGroup *box_; @@ -141,9 +143,9 @@ public: UI::Event OnChoice; protected: - virtual bool FillVertical() const override { return false; } - virtual bool ShowButtons() const override { return showButtons_; } - virtual void CreatePopupContents(UI::ViewGroup *parent) override; + bool FillVertical() const override { return false; } + bool ShowButtons() const override { return showButtons_; } + void CreatePopupContents(UI::ViewGroup *parent) override; UI::StringVectorListAdaptor adaptor_; UI::ListView *listView_ = nullptr; @@ -162,9 +164,9 @@ public: UI::Event OnChoice; protected: - virtual bool FillVertical() const override { return false; } - virtual bool ShowButtons() const override { return true; } - virtual void CreatePopupContents(UI::ViewGroup *parent) override; + bool FillVertical() const override { return false; } + bool ShowButtons() const override { return true; } + void CreatePopupContents(UI::ViewGroup *parent) override; private: void OnCompleted(DialogResult result) override; @@ -180,7 +182,7 @@ class SliderPopupScreen : public PopupScreen { public: SliderPopupScreen(int *value, int minValue, int maxValue, const std::string &title, int step = 1, const std::string &units = "") : PopupScreen(title, "OK", "Cancel"), units_(units), value_(value), minValue_(minValue), maxValue_(maxValue), step_(step) {} - virtual void CreatePopupContents(ViewGroup *parent) override; + void CreatePopupContents(ViewGroup *parent) override; void SetNegativeDisable(const std::string &str) { negativeLabel_ = str; @@ -196,7 +198,7 @@ private: EventReturn OnIncrease(EventParams ¶ms); EventReturn OnTextChange(EventParams ¶ms); EventReturn OnSliderChange(EventParams ¶ms); - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; Slider *slider_ = nullptr; UI::TextEdit *edit_ = nullptr; std::string units_; @@ -225,7 +227,7 @@ private: EventReturn OnDecrease(EventParams ¶ms); EventReturn OnTextChange(EventParams ¶ms); EventReturn OnSliderChange(EventParams ¶ms); - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; UI::SliderFloat *slider_; UI::TextEdit *edit_; std::string units_; @@ -243,14 +245,14 @@ class TextEditPopupScreen : public PopupScreen { public: TextEditPopupScreen(std::string *value, const std::string &placeholder, const std::string &title, int maxLen) : PopupScreen(title, "OK", "Cancel"), value_(value), placeholder_(placeholder), maxLen_(maxLen) {} - virtual void CreatePopupContents(ViewGroup *parent) override; + void CreatePopupContents(ViewGroup *parent) override; const char *tag() const override { return "TextEditPopup"; } Event OnChange; private: - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; TextEdit *edit_; std::string *value_; std::string textEditValue_; @@ -258,13 +260,45 @@ private: int maxLen_; }; +// TODO: Break out a lot of popup stuff from UIScreen.h. + +struct ContextMenuItem { + const char *text; + const char *imageID; +}; + +// Once a selection has been made, +class PopupContextMenuScreen : public PopupScreen { +public: + PopupContextMenuScreen(const ContextMenuItem *items, size_t itemCount, I18NCategory *category, UI::View *sourceView); + void CreatePopupContents(ViewGroup *parent) override; + + const char *tag() const override { return "ContextMenuPopup"; } + + void SetEnabled(size_t index, bool enabled) { + enabled_[index] = enabled; + } + + UI::Event OnChoice; + +protected: + bool HasTitleBar() const override { return false; } + +private: + const ContextMenuItem *items_; + size_t itemCount_; + I18NCategory *category_; + UI::View *sourceView_; + std::vector enabled_; +}; + class AbstractChoiceWithValueDisplay : public UI::Choice { public: AbstractChoiceWithValueDisplay(const std::string &text, LayoutParams *layoutParams = nullptr) : Choice(text, layoutParams) { } - virtual void Draw(UIContext &dc) override; + void Draw(UIContext &dc) override; void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; protected: @@ -344,7 +378,7 @@ public: } protected: - void PostChoiceCallback(int num) { + void PostChoiceCallback(int num) override { *valueStr_ = choices_[num]; } @@ -386,7 +420,7 @@ private: std::string negativeLabel_; std::string units_; ScreenManager *screenManager_; - bool restoreFocus_; + bool restoreFocus_ = false; }; class PopupSliderChoiceFloat : public AbstractChoiceWithValueDisplay { @@ -423,7 +457,7 @@ private: std::string zeroLabel_; std::string units_; ScreenManager *screenManager_; - bool restoreFocus_; + bool restoreFocus_ = false; bool liveUpdate_ = false; bool hasDropShadow_ = true; }; @@ -463,8 +497,8 @@ public: private: std::string ValueText() const override; - int *iValue_ = nullptr; std::string *sValue_ = nullptr; + int *iValue_ = nullptr; const char *category_ = nullptr; std::string (*translateCallback_)(const char *value) = nullptr; }; diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 72d3443ab0..8be9b3076d 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -16,15 +16,15 @@ #include "Common/System/System.h" #include "Common/TimeUtil.h" #include "Common/StringUtils.h" +#include "Common/Log.h" namespace UI { -const float ITEM_HEIGHT = 64.f; -const float MIN_TEXT_SCALE = 0.8f; -const float MAX_ITEM_SIZE = 65535.0f; +static constexpr Size ITEM_HEIGHT = 64.f; +static constexpr float MIN_TEXT_SCALE = 0.8f; +static constexpr float MAX_ITEM_SIZE = 65535.0f; void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured) { - *measured = sz; if (sz == WRAP_CONTENT) { if (spec.type == UNSPECIFIED) *measured = contentWidth; @@ -40,6 +40,8 @@ void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measure *measured = spec.size; } else if (spec.type == EXACTLY || (spec.type == AT_MOST && *measured > spec.size)) { *measured = spec.size; + } else { + *measured = sz; } } @@ -167,7 +169,7 @@ void View::PersistData(PersistStatus status, std::string anonId, PersistMap &sto } } -Point View::GetFocusPosition(FocusDirection dir) { +Point View::GetFocusPosition(FocusDirection dir) const { // The +2/-2 is some extra fudge factor to cover for views sitting right next to each other. // Distance zero yields strange results otherwise. switch (dir) { @@ -226,11 +228,13 @@ void Clickable::FocusChanged(int focusFlags) { } } -void Clickable::Touch(const TouchInput &input) { +bool Clickable::Touch(const TouchInput &input) { + bool contains = bounds_.Contains(input.x, input.y); + if (!IsEnabled()) { dragging_ = false; down_ = false; - return; + return contains; } if (input.flags & TOUCH_DOWN) { @@ -255,6 +259,7 @@ void Clickable::Touch(const TouchInput &input) { downCountDown_ = 0; dragging_ = false; } + return contains; } static bool MatchesKeyDef(const std::vector &defs, const KeyInput &key) { @@ -350,21 +355,24 @@ bool Clickable::Key(const KeyInput &key) { return ret; } -void StickyChoice::Touch(const TouchInput &input) { +bool StickyChoice::Touch(const TouchInput &touch) { + bool contains = bounds_.Contains(touch.x, touch.y); dragging_ = false; if (!IsEnabled()) { down_ = false; - return; + return contains; } - if (input.flags & TOUCH_DOWN) { - if (bounds_.Contains(input.x, input.y)) { + if (touch.flags & TOUCH_DOWN) { + if (contains) { if (IsFocusMovementEnabled()) SetFocusedView(this); down_ = true; Click(); + return true; } } + return false; } bool StickyChoice::Key(const KeyInput &key) { @@ -407,6 +415,7 @@ void ClickableItem::GetContentDimensions(const UIContext &dc, float &w, float &h ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParams) { if (!layoutParams) { + // The default LayoutParams assigned by View::View defaults to WRAP_CONTENT/WRAP_CONTENT. if (layoutParams_->width == WRAP_CONTENT) layoutParams_->width = FILL_PARENT; } @@ -483,7 +492,7 @@ void Choice::Draw(UIContext &dc) { if (image_.isValid() && text_.empty()) { dc.Draw()->DrawImageRotated(image_, bounds_.centerX(), bounds_.centerY(), imgScale_, imgRot_, style.fgColor, imgFlipH_); - } else { + } else if (!text_.empty()) { dc.SetFontStyle(dc.theme->uiFont); int paddingX = 12; @@ -491,6 +500,7 @@ void Choice::Draw(UIContext &dc) { if (image_.isValid()) { const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(image_); + _dbg_assert_(image); paddingX += image->w + 6; availWidth -= image->w + 6; // TODO: Use scale rotation and flip here as well (DrawImageRotated is always ALIGN_CENTER for now) @@ -690,28 +700,55 @@ void CheckBox::Draw(UIContext &dc) { if (!IsEnabled()) { style = dc.theme->itemDisabledStyle; } - if (HasFocus()) { - style = dc.theme->itemFocusedStyle; - } - if (down_) { - style = dc.theme->itemDownStyle; + ImageID image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; + + // In image mode, light up instead of showing a checkbox. + if (imageID_.isValid()) { + image = imageID_; + if (Toggled()) { + if (HasFocus()) { + style = dc.theme->itemDownStyle; + } else { + style = dc.theme->itemFocusedStyle; + } + } else { + if (HasFocus()) { + style = dc.theme->itemDownStyle; + } else { + style = dc.theme->itemStyle; + } + } + + if (down_) { + style.background.color = lightenColor(style.background.color); + } + + } else { + if (HasFocus()) { + style = dc.theme->itemFocusedStyle; + } + if (down_) { + style = dc.theme->itemDownStyle; + } } + dc.SetFontStyle(dc.theme->uiFont); - ClickableItem::Draw(dc); + DrawBG(dc, style); - ImageID image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); const int paddingX = 12; // Padding right of the checkbox image too. const float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX; - float scale = CalculateTextScale(dc, availWidth); - dc.SetFontScale(scale, scale); - Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h); - dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); + if (!text_.empty()) { + float scale = CalculateTextScale(dc, availWidth); + dc.SetFontScale(scale, scale); + Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h); + dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); + } dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); dc.SetFontScale(1.0f, 1.0f); } @@ -737,24 +774,41 @@ float CheckBox::CalculateTextScale(const UIContext &dc, float availWidth) const void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) const { ImageID image = Toggled() ? dc.theme->checkOn : dc.theme->checkOff; + if (imageID_.isValid()) { + image = imageID_; + } + float imageW, imageH; dc.Draw()->MeasureImage(image, &imageW, &imageH); const int paddingX = 12; + + if (imageID_.isValid()) { + w = imageW + paddingX * 2; + h = std::max(imageH, ITEM_HEIGHT); + return; + } + + // The below code is kinda wacky, we shouldn't involve bounds_ here. + // Padding right of the checkbox image too. float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX; if (availWidth < 0.0f) { // Let it have as much space as it needs. availWidth = MAX_ITEM_SIZE; } - float scale = CalculateTextScale(dc, availWidth); - float actualWidth, actualHeight; - Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); + if (!text_.empty()) { + float scale = CalculateTextScale(dc, availWidth); + float actualWidth, actualHeight; + Bounds availBounds(0, 0, availWidth, bounds_.h); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); + h = std::max(actualHeight, ITEM_HEIGHT); + } else { + h = std::max(imageH, ITEM_HEIGHT); + } w = bounds_.w; - h = std::max(actualHeight, ITEM_HEIGHT); } void BitCheckBox::Toggle() { @@ -1069,12 +1123,14 @@ static std::string FirstLine(const std::string &text) { return text; } -void TextEdit::Touch(const TouchInput &touch) { +bool TextEdit::Touch(const TouchInput &touch) { if (touch.flags & TOUCH_DOWN) { if (bounds_.Contains(touch.x, touch.y)) { SetFocusedView(this, true); + return true; } } + return false; } bool TextEdit::Key(const KeyInput &input) { @@ -1259,14 +1315,15 @@ void Spinner::Draw(UIContext &dc) { } } -void TriggerButton::Touch(const TouchInput &input) { +bool TriggerButton::Touch(const TouchInput &input) { + bool contains = bounds_.Contains(input.x, input.y); if (input.flags & TOUCH_DOWN) { - if (bounds_.Contains(input.x, input.y)) { + if (contains) { down_ |= 1 << input.id; } } if (input.flags & TOUCH_MOVE) { - if (bounds_.Contains(input.x, input.y)) + if (contains) down_ |= 1 << input.id; else down_ &= ~(1 << input.id); @@ -1281,6 +1338,8 @@ void TriggerButton::Touch(const TouchInput &input) { } else { *bitField_ &= ~bit_; } + + return contains; } void TriggerButton::Draw(UIContext &dc) { @@ -1344,9 +1403,10 @@ bool Slider::ApplyKey(int keyCode) { return true; } -void Slider::Touch(const TouchInput &input) { +bool Slider::Touch(const TouchInput &input) { // Calling it afterwards, so dragging_ hasn't been set false yet when checking it above. - Clickable::Touch(input); + bool contains = Clickable::Touch(input); + if (dragging_) { float relativeX = (input.x - (bounds_.x + paddingLeft_)) / (bounds_.w - paddingLeft_ - paddingRight_); *value_ = floorf(relativeX * (maxValue_ - minValue_) + minValue_ + 0.5f); @@ -1360,6 +1420,7 @@ void Slider::Touch(const TouchInput &input) { // Cancel any key repeat. repeat_ = -1; + return contains; } void Slider::Clamp() { @@ -1470,8 +1531,8 @@ bool SliderFloat::ApplyKey(int keyCode) { return true; } -void SliderFloat::Touch(const TouchInput &input) { - Clickable::Touch(input); +bool SliderFloat::Touch(const TouchInput &input) { + bool contains = Clickable::Touch(input); if (dragging_) { float relativeX = (input.x - (bounds_.x + paddingLeft_)) / (bounds_.w - paddingLeft_ - paddingRight_); *value_ = (relativeX * (maxValue_ - minValue_) + minValue_); @@ -1485,6 +1546,7 @@ void SliderFloat::Touch(const TouchInput &input) { // Cancel any key repeat. repeat_ = -1; + return contains; } void SliderFloat::Clamp() { diff --git a/Common/UI/View.h b/Common/UI/View.h index 0a78433073..f3c54a0a3d 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -128,10 +128,10 @@ enum FocusDirection { FOCUS_NEXT_PAGE, }; -enum { - WRAP_CONTENT = -1, - FILL_PARENT = -2, -}; +typedef float Size; // can also be WRAP_CONTENT or FILL_PARENT. + +static constexpr Size WRAP_CONTENT = -1.0f; +static constexpr Size FILL_PARENT = -2.0f; // Gravity enum Gravity { @@ -174,8 +174,6 @@ enum class BorderStyle { ITEM_DOWN_BG, }; -typedef float Size; // can also be WRAP_CONTENT or FILL_PARENT. - enum Orientation { ORIENT_HORIZONTAL, ORIENT_VERTICAL, @@ -289,6 +287,13 @@ struct Margins { int vert() const { return top + bottom; } + void SetAll(float f) { + int8_t i = (int)f; + top = i; + bottom = i; + left = i; + right = i; + } int8_t top; int8_t bottom; @@ -377,7 +382,7 @@ public: // Can even be called on a different thread! This is to really minimize latency, and decouple // touch response from the frame rate. Same with Key and Axis. virtual bool Key(const KeyInput &input) { return false; } - virtual void Touch(const TouchInput &input) {} + virtual bool Touch(const TouchInput &input) { return true; } virtual void Axis(const AxisInput &input) {} virtual void Update(); @@ -463,7 +468,7 @@ public: virtual bool IsViewGroup() const { return false; } virtual bool ContainsSubview(const View *view) const { return false; } - Point GetFocusPosition(FocusDirection dir); + Point GetFocusPosition(FocusDirection dir) const; template T *AddTween(T *t) { @@ -503,7 +508,7 @@ public: : View(layoutParams) {} bool Key(const KeyInput &input) override { return false; } - void Touch(const TouchInput &input) override {} + bool Touch(const TouchInput &input) override { return false; } bool CanBeFocused() const override { return false; } }; @@ -514,7 +519,7 @@ public: Clickable(LayoutParams *layoutParams); bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void FocusChanged(int focusFlags) override; @@ -604,7 +609,7 @@ public: void Draw(UIContext &dc) override; std::string DescribeText() const override; bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; void SetShowPercent(bool s) { showPercent_ = s; } @@ -635,7 +640,7 @@ public: void Draw(UIContext &dc) override; std::string DescribeText() const override; bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -663,7 +668,7 @@ public: TriggerButton(uint32_t *bitField, uint32_t bit, ImageID imageBackground, ImageID imageForeground, LayoutParams *layoutParams) : View(layoutParams), down_(0.0), bitField_(bitField), bit_(bit), imageBackground_(imageBackground), imageForeground_(imageForeground) {} - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -757,7 +762,7 @@ public: : Choice(buttonImage, layoutParams) {} bool Key(const KeyInput &key) override; - void Touch(const TouchInput &touch) override; + bool Touch(const TouchInput &touch) override; void FocusChanged(int focusFlags) override; void Press() { down_ = true; dragging_ = false; } @@ -829,11 +834,17 @@ private: class CheckBox : public ClickableItem { public: - CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = 0) + CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = nullptr) : ClickableItem(layoutParams), toggle_(toggle), text_(text), smallText_(smallText) { OnClick.Handle(this, &CheckBox::OnClicked); } + // Image-only "checkbox", lights up instead of showing a checkmark. + CheckBox(bool *toggle, ImageID imageID, LayoutParams *layoutParams = nullptr) + : ClickableItem(layoutParams), toggle_(toggle), imageID_(imageID) { + OnClick.Handle(this, &CheckBox::OnClicked); + } + void Draw(UIContext &dc) override; std::string DescribeText() const override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -848,6 +859,7 @@ private: bool *toggle_; std::string text_; std::string smallText_; + ImageID imageID_; }; class BitCheckBox : public CheckBox { @@ -945,7 +957,7 @@ public: void Draw(UIContext &dc) override; std::string DescribeText() const override; bool Key(const KeyInput &key) override; - void Touch(const TouchInput &touch) override; + bool Touch(const TouchInput &touch) override; Event OnTextChange; Event OnEnter; diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f4fb73ffa3..f8405fbb97 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -22,7 +22,7 @@ namespace UI { -const float ITEM_HEIGHT = 64.f; +static constexpr Size ITEM_HEIGHT = 64.f; void ApplyGravity(const Bounds outer, const Margins &margins, float w, float h, int gravity, Bounds &inner) { inner.w = w; @@ -31,13 +31,13 @@ void ApplyGravity(const Bounds outer, const Margins &margins, float w, float h, switch (gravity & G_HORIZMASK) { case G_LEFT: inner.x = outer.x + margins.left; break; case G_RIGHT: inner.x = outer.x + outer.w - w - margins.right; break; - case G_HCENTER: inner.x = outer.x + (outer.w - w) / 2; break; + case G_HCENTER: inner.x = outer.x + (outer.w - w) * 0.5f; break; } switch (gravity & G_VERTMASK) { case G_TOP: inner.y = outer.y + margins.top; break; case G_BOTTOM: inner.y = outer.y + outer.h - h - margins.bottom; break; - case G_VCENTER: inner.y = outer.y + (outer.h - h) / 2; break; + case G_VCENTER: inner.y = outer.y + (outer.h - h) * 0.5f; break; } } @@ -87,12 +87,23 @@ void ViewGroup::PersistData(PersistStatus status, std::string anonId, PersistMap } } -void ViewGroup::Touch(const TouchInput &input) { +bool ViewGroup::Touch(const TouchInput &input) { std::lock_guard guard(modifyLock_); + bool any = false; for (auto iter = views_.begin(); iter != views_.end(); ++iter) { // TODO: If there is a transformation active, transform input coordinates accordingly. - if ((*iter)->GetVisibility() == V_VISIBLE) - (*iter)->Touch(input); + if ((*iter)->GetVisibility() == V_VISIBLE) { + bool touch = (*iter)->Touch(input); + any = any || touch; + if (exclusiveTouch_ && touch && (input.flags & TOUCH_DOWN)) { + break; + } + } + } + if (clickableBackground_) { + return any || bounds_.Contains(input.x, input.y); + } else { + return any; } } @@ -260,11 +271,12 @@ static float HorizontalOverlap(const Bounds &a, const Bounds &b) { // okay they do overlap. Let's clip. float maxMin = std::max(a.x, b.x); float minMax = std::min(a.x2(), b.x2()); + float minW = std::min(a.w, b.w); float overlap = minMax - maxMin; - if (overlap < 0.0f) + if (overlap < 0.0f || minW <= 0.0f) return 0.0f; else - return std::min(1.0f, overlap / std::min(a.w, b.w)); + return std::min(1.0f, overlap / minW); } // Returns the percentage the smaller one overlaps the bigger one. @@ -274,14 +286,15 @@ static float VerticalOverlap(const Bounds &a, const Bounds &b) { // okay they do overlap. Let's clip. float maxMin = std::max(a.y, b.y); float minMax = std::min(a.y2(), b.y2()); + float minH = std::min(a.h, b.h); float overlap = minMax - maxMin; - if (overlap < 0.0f) + if (overlap < 0.0f || minH <= 0.0f) return 0.0f; else - return std::min(1.0f, overlap / std::min(a.h, b.h)); + return std::min(1.0f, overlap / minH); } -float GetTargetScore(const Point &originPos, int originIndex, View *origin, View *destination, FocusDirection direction) { +float GetTargetScore(const Point &originPos, int originIndex, const View *origin, const View *destination, FocusDirection direction) { // Skip labels and things like that. if (!destination->CanBeFocused()) return 0.0f; @@ -296,6 +309,9 @@ float GetTargetScore(const Point &originPos, int originIndex, View *origin, View float dy = destPos.y - originPos.y; float distance = sqrtf(dx*dx + dy*dy); + if (distance == 0.0f) { + distance = 0.001f; + } float overlap = 0.0f; float dirX = dx / distance; float dirY = dy / distance; @@ -378,7 +394,7 @@ float GetTargetScore(const Point &originPos, int originIndex, View *origin, View } } -float GetDirectionScore(int originIndex, View *origin, View *destination, FocusDirection direction) { +static float GetDirectionScore(int originIndex, const View *origin, View *destination, FocusDirection direction) { Point originPos = origin->GetFocusPosition(direction); return GetTargetScore(originPos, originIndex, origin, destination, direction); } @@ -498,8 +514,9 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v float sum = 0.0f; float maxOther = 0.0f; float totalWeight = 0.0f; - float weightSum = 0.0f; - float weightZeroSum = 0.0f; + + float weightSum = 0.0f; // Total sum of weights + float weightZeroSum = 0.0f; // Sum of sizes of things with weight 0.0, a bit confusingly named int numVisible = 0; @@ -522,19 +539,19 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec v = vert; if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f) v = MeasureSpec(AT_MOST, measuredHeight_); - view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert()); - if (horiz.type == AT_MOST && view->GetMeasuredWidth() + margins.horiz() > horiz.size - weightZeroSum) { + view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert() - (float)padding.vert()); + if (horiz.type == AT_MOST && view->GetMeasuredWidth() + margins.horiz() + padding.horiz() > horiz.size - weightZeroSum) { // Try again, this time with AT_MOST. - view->Measure(dc, horiz, v - (float)margins.vert()); + view->Measure(dc, horiz, v - (float)margins.vert() - (float)padding.vert()); } } else if (orientation_ == ORIENT_VERTICAL) { MeasureSpec h = horiz; if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f) h = MeasureSpec(AT_MOST, measuredWidth_); - view->Measure(dc, h - (float)margins.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_)); - if (vert.type == AT_MOST && view->GetMeasuredHeight() + margins.vert() > vert.size - weightZeroSum) { + view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_)); + if (vert.type == AT_MOST && view->GetMeasuredHeight() + margins.vert() + padding.horiz() > vert.size - weightZeroSum) { // Try again, this time with AT_MOST. - view->Measure(dc, h - (float)margins.horiz(), vert); + view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), vert); } } @@ -558,12 +575,12 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } } - weightZeroSum += spacing_ * (numVisible - 1); + weightZeroSum += spacing_ * (numVisible - 1); // +(orientation_ == ORIENT_HORIZONTAL) ? padding.horiz() : padding.vert(); // Alright, got the sum. Let's take the remaining space after the fixed-size views, // and distribute among the weighted ones. if (orientation_ == ORIENT_HORIZONTAL) { - MeasureBySpec(layoutParams_->width, weightZeroSum, horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, weightZeroSum + padding.horiz(), horiz, &measuredWidth_); // If we've got stretch, allow growing to fill the parent. float allowedWidth = measuredWidth_; @@ -571,14 +588,17 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v allowedWidth = horiz.size; } - float usedWidth = 0.0f; + float usedWidth = 0.0f + padding.horiz(); // Redistribute the stretchy ones! and remeasure the children! for (View *view : views_) { if (view->GetVisibility() == V_GONE) continue; - const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); + // FILL_PARENT is not appropriate in this direction. It gets ignored though. + // We have a bit too many of these due to the hack in the ClickableItem constructor. + // _dbg_assert_(view->GetLayoutParams()->width != UI::FILL_PARENT); + const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); if (linLayoutParams && linLayoutParams->weight > 0.0f) { Margins margins = defaultMargins_; if (linLayoutParams->HasMargins()) @@ -587,11 +607,15 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f) v = MeasureSpec(AT_MOST, measuredHeight_); float unit = (allowedWidth - weightZeroSum) / weightSum; + if (weightSum == 0.0f) { + // We must have gotten an inf. + unit = 1.0f; + } MeasureSpec h(AT_MOST, unit * linLayoutParams->weight - margins.horiz()); if (horiz.type == EXACTLY) { h.type = EXACTLY; } - view->Measure(dc, h, v - (float)margins.vert()); + view->Measure(dc, h, v - (float)margins.vert() - (float)padding.vert()); usedWidth += view->GetMeasuredWidth(); maxOther = std::max(maxOther, view->GetMeasuredHeight() + margins.vert()); } @@ -602,9 +626,9 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } // Measure here in case maxOther moved (can happen due to word wrap.) - MeasureBySpec(layoutParams_->height, maxOther, vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, maxOther + padding.vert(), vert, &measuredHeight_); } else { - MeasureBySpec(layoutParams_->height, weightZeroSum, vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, weightZeroSum + padding.vert(), vert, &measuredHeight_); // If we've got stretch, allow growing to fill the parent. float allowedHeight = measuredHeight_; @@ -612,14 +636,17 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v allowedHeight = vert.size; } - float usedHeight = 0.0f; + float usedHeight = 0.0f + padding.vert(); // Redistribute the stretchy ones! and remeasure the children! for (View *view : views_) { if (view->GetVisibility() == V_GONE) continue; - const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); + // FILL_PARENT is not appropriate in this direction. It gets ignored though. + // We have a bit too many of these due to the hack in the ClickableItem constructor. + // _dbg_assert_(view->GetLayoutParams()->height != UI::FILL_PARENT); + const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As(); if (linLayoutParams && linLayoutParams->weight > 0.0f) { Margins margins = defaultMargins_; if (linLayoutParams->HasMargins()) @@ -628,11 +655,15 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f) h = MeasureSpec(AT_MOST, measuredWidth_); float unit = (allowedHeight - weightZeroSum) / weightSum; + if (weightSum == 0.0f) { + // We must have gotten an inf. + unit = 1.0f; + } MeasureSpec v(AT_MOST, unit * linLayoutParams->weight - margins.vert()); if (vert.type == EXACTLY) { v.type = EXACTLY; } - view->Measure(dc, h - (float)margins.horiz(), v); + view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), v); usedHeight += view->GetMeasuredHeight(); maxOther = std::max(maxOther, view->GetMeasuredWidth() + margins.horiz()); } @@ -643,7 +674,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } // Measure here in case maxOther moved (can happen due to word wrap.) - MeasureBySpec(layoutParams_->width, maxOther, horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, maxOther + padding.horiz(), horiz, &measuredWidth_); } } @@ -655,13 +686,13 @@ void LinearLayout::Layout() { float pos; if (orientation_ == ORIENT_HORIZONTAL) { - pos = bounds.x; - itemBounds.y = bounds.y; - itemBounds.h = measuredHeight_; + pos = bounds.x + padding.left; + itemBounds.y = bounds.y + padding.top; + itemBounds.h = measuredHeight_ - padding.vert(); } else { - pos = bounds.y; - itemBounds.x = bounds.x; - itemBounds.w = measuredWidth_; + pos = bounds.y + padding.top; + itemBounds.x = bounds.x + padding.left; + itemBounds.w = measuredWidth_ - padding.horiz(); } for (size_t i = 0; i < views_.size(); i++) { @@ -728,8 +759,8 @@ void FrameLayout::Layout() { bounds.w = w; bounds.h = h; - bounds.x = bounds_.x + (measuredWidth_ - w) / 2; - bounds.y = bounds_.y + (measuredWidth_ - h) / 2; + bounds.x = bounds_.x + (measuredWidth_ - w) * 0.5f; + bounds.y = bounds_.y + (measuredWidth_ - h) * 0.5f; views_[i]->SetBounds(bounds); } } @@ -826,13 +857,21 @@ bool ScrollView::Key(const KeyInput &input) { if (visibility_ != V_VISIBLE) return ViewGroup::Key(input); + float scrollSpeed = 250; + switch (input.deviceId) { + case DEVICE_ID_XR_CONTROLLER_LEFT: + case DEVICE_ID_XR_CONTROLLER_RIGHT: + scrollSpeed = 50; + break; + } + if (input.flags & KEY_DOWN) { switch (input.keyCode) { case NKCODE_EXT_MOUSEWHEEL_UP: - ScrollRelative(-250); + ScrollRelative(-scrollSpeed); break; case NKCODE_EXT_MOUSEWHEEL_DOWN: - ScrollRelative(250); + ScrollRelative(scrollSpeed); break; } } @@ -842,7 +881,7 @@ bool ScrollView::Key(const KeyInput &input) { const float friction = 0.92f; const float stop_threshold = 0.1f; -void ScrollView::Touch(const TouchInput &input) { +bool ScrollView::Touch(const TouchInput &input) { if ((input.flags & TOUCH_DOWN) && scrollTouchId_ == -1) { scrollStart_ = scrollPos_; inertia_ = 0.0f; @@ -876,7 +915,9 @@ void ScrollView::Touch(const TouchInput &input) { } if (!(input.flags & TOUCH_DOWN) || bounds_.Contains(input.x, input.y)) { - ViewGroup::Touch(input2); + return ViewGroup::Touch(input2); + } else { + return false; } } @@ -887,6 +928,8 @@ void ScrollView::Draw(UIContext &dc) { } dc.PushScissor(bounds_); + dc.FillRect(bg_, bounds_); + // For debugging layout issues, this can be useful. // dc.FillRect(Drawable(0x60FF00FF), bounds_); views_[0]->Draw(dc); @@ -895,7 +938,7 @@ void ScrollView::Draw(UIContext &dc) { float childHeight = views_[0]->GetBounds().h; float scrollMax = std::max(0.0f, childHeight - bounds_.h); - float ratio = bounds_.h / views_[0]->GetBounds().h; + float ratio = bounds_.h / std::max(0.01f, views_[0]->GetBounds().h); float bobWidth = 5; if (ratio < 1.0f && scrollMax > 0.0f) { @@ -920,7 +963,7 @@ bool ScrollView::SubviewFocused(View *view) { float visibleSize = orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w; float visibleEnd = scrollPos_ + visibleSize; - float viewStart, viewEnd; + float viewStart = 0.0f, viewEnd = 0.0f; switch (orientation_) { case ORIENT_HORIZONTAL: viewStart = layoutScrollPos_ + vBounds.x - bounds_.x; @@ -1037,16 +1080,17 @@ void ScrollView::ScrollRelative(float distance) { } float ScrollView::ClampedScrollPos(float pos) { - if (!views_.size()) { + if (!views_.size() || bounds_.h == 0.0f) { return 0.0f; } float childSize = orientation_ == ORIENT_VERTICAL ? views_[0]->GetBounds().h : views_[0]->GetBounds().w; - float scrollMax = std::max(0.0f, childSize - (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w)); + float containerSize = (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w); + float scrollMax = std::max(0.0f, childSize - containerSize); Gesture gesture = orientation_ == ORIENT_VERTICAL ? GESTURE_DRAG_VERTICAL : GESTURE_DRAG_HORIZONTAL; - if (scrollTouchId_ >= 0 && gesture_.IsGestureActive(gesture, scrollTouchId_) && bounds_.h > 0) { + if (scrollTouchId_ >= 0 && gesture_.IsGestureActive(gesture, scrollTouchId_) && bounds_.h > 0.0f) { float maxPull = bounds_.h * 0.1f; if (pos < 0.0f) { float dist = std::min(-pos * (1.0f / bounds_.h), 1.0f); @@ -1065,7 +1109,9 @@ float ScrollView::ClampedScrollPos(float pos) { if (pos > scrollMax && pos > scrollMax + pull_) { pos = scrollMax + pull_; } - + if (childSize < containerSize && alignOpposite_) { + pos = -(containerSize - childSize); + } return pos; } @@ -1240,6 +1286,9 @@ void AnchorLayout::Layout() { if (center) { vBounds.x += vBounds.w * 0.5f; } + } else { + // Both left and right are NONE. Center. + vBounds.x = (bounds_.w - vBounds.w) / 2.0f + bounds_.x; } if (top > NONE) { @@ -1250,6 +1299,9 @@ void AnchorLayout::Layout() { vBounds.y = bounds_.y2() - bottom - vBounds.h; if (center) vBounds.y += vBounds.h * 0.5f; + } else { + // Both top and bottom are NONE. Center. + vBounds.y = (bounds_.h - vBounds.h) / 2.0f + bounds_.y; } views_[i]->SetBounds(vBounds); @@ -1258,7 +1310,7 @@ void AnchorLayout::Layout() { } GridLayout::GridLayout(GridLayoutSettings settings, LayoutParams *layoutParams) - : ViewGroup(layoutParams), settings_(settings), numColumns_(1) { + : ViewGroup(layoutParams), settings_(settings) { if (settings.orientation != ORIENT_HORIZONTAL) ERROR_LOG(SYSTEM, "GridLayout: Vertical layouts not yet supported"); } @@ -1439,7 +1491,7 @@ void TabHolder::PersistData(PersistStatus status, std::string anonId, PersistMap } ChoiceStrip::ChoiceStrip(Orientation orientation, LayoutParams *layoutParams) - : LinearLayout(orientation, layoutParams), selected_(0), topTabs_(false) { + : LinearLayout(orientation, layoutParams) { SetSpacing(0.0f); } @@ -1551,6 +1603,7 @@ StickyChoice *ChoiceStrip::Choice(int index) { return static_cast(views_[index]); return nullptr; } + ListView::ListView(ListAdaptor *a, std::set hidden, LayoutParams *layoutParams) : ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a), maxHeight_(0), hidden_(hidden) { diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 5b552c5f0f..32ddb8eb56 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -24,27 +24,23 @@ struct NeighborResult { class ViewGroup : public View { public: ViewGroup(LayoutParams *layoutParams = 0) : View(layoutParams) {} - virtual ~ViewGroup(); + ~ViewGroup(); // Pass through external events to children. - virtual bool Key(const KeyInput &input) override; - virtual void Touch(const TouchInput &input) override; - virtual void Axis(const AxisInput &input) override; + bool Key(const KeyInput &input) override; + bool Touch(const TouchInput &input) override; + void Axis(const AxisInput &input) override; // By default, a container will layout to its own bounds. - virtual void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override = 0; - virtual void Layout() override = 0; - virtual void Update() override; - virtual void Query(float x, float y, std::vector &list) override; + void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override = 0; + void Layout() override = 0; + void Update() override; + void Query(float x, float y, std::vector &list) override; - virtual void DeviceLost() override; - virtual void DeviceRestored(Draw::DrawContext *draw) override; + void DeviceLost() override; + void DeviceRestored(Draw::DrawContext *draw) override; - virtual void Draw(UIContext &dc) override; - - // These should be unused. - virtual float GetContentWidth() const { return 0.0f; } - virtual float GetContentHeight() const { return 0.0f; } + void Draw(UIContext &dc) override; // Takes ownership! DO NOT add a view to multiple parents! template @@ -54,8 +50,8 @@ public: return view; } - virtual bool SetFocus() override; - virtual bool SubviewFocused(View *view) override; + bool SetFocus() override; + bool SubviewFocused(View *view) override; virtual void RemoveSubview(View *view); void SetDefaultFocusView(View *view) { defaultFocusView_ = view; } @@ -77,6 +73,8 @@ public: int GetNumSubviews() const { return (int)views_.size(); } void SetHasDropShadow(bool has) { hasDropShadow_ = has; } void SetDropShadowExpand(float s) { dropShadowExpand_ = s; } + void SetExclusiveTouch(bool exclusive) { exclusiveTouch_ = exclusive; } + void SetClickableBackground(bool clickableBackground) { clickableBackground_ = clickableBackground; } void Lock() { modifyLock_.lock(); } void Unlock() { modifyLock_.unlock(); } @@ -95,13 +93,16 @@ protected: Drawable bg_; float dropShadowExpand_ = 0.0f; bool hasDropShadow_ = false; + bool clickableBackground_ = false; bool clip_ = false; + bool exclusiveTouch_ = false; }; // A frame layout contains a single child view (normally). // It simply centers the child view. class FrameLayout : public ViewGroup { public: + FrameLayout(LayoutParams *layoutParams = nullptr) : ViewGroup(layoutParams) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; }; @@ -111,9 +112,7 @@ const float NONE = -FLT_MAX; class AnchorLayoutParams : public LayoutParams { public: AnchorLayoutParams(Size w, Size h, float l, float t, float r, float b, bool c = false) - : LayoutParams(w, h, LP_ANCHOR), left(l), top(t), right(r), bottom(b), center(c) { - - } + : LayoutParams(w, h, LP_ANCHOR), left(l), top(t), right(r), bottom(b), center(c) {} // There's a small hack here to make this behave more intuitively - AnchorLayout ordinarily ignores FILL_PARENT. AnchorLayoutParams(Size w, Size h, bool c = false) : LayoutParams(w, h, LP_ANCHOR), left(0), top(0), right(w == FILL_PARENT ? 0 : NONE), bottom(h == FILL_PARENT ? 0 : NONE), center(c) { @@ -123,6 +122,7 @@ public: // These are not bounds, but distances from the container edges. // Set to NONE to not attach this edge to the container. + // If two opposite edges are NONE, centering will happen. float left, top, right, bottom; bool center; // If set, only two "sides" can be set, and they refer to the center, not the edge, of the view being layouted. @@ -133,7 +133,7 @@ public: class AnchorLayout : public ViewGroup { public: - AnchorLayout(LayoutParams *layoutParams = 0) : ViewGroup(layoutParams), overflow_(true) {} + AnchorLayout(LayoutParams *layoutParams = 0) : ViewGroup(layoutParams) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; void Overflow(bool allow) { @@ -143,7 +143,7 @@ public: private: void MeasureViews(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert); - bool overflow_; + bool overflow_ = true; }; class LinearLayoutParams : public LayoutParams { @@ -155,7 +155,7 @@ public: LinearLayoutParams(float wgt, const Margins &mgn) : LayoutParams(LP_LINEAR), weight(wgt), gravity(G_TOPLEFT), margins(mgn), hasMargins_(true) {} LinearLayoutParams(Size w, Size h, float wgt = 0.0f, Gravity grav = G_TOPLEFT) - : LayoutParams(w, h, LP_LINEAR), weight(wgt), gravity(grav), hasMargins_(false) {} + : LayoutParams(w, h, LP_LINEAR), weight(wgt), gravity(grav), margins(0), hasMargins_(false) {} LinearLayoutParams(Size w, Size h, float wgt, Gravity grav, const Margins &mgn) : LayoutParams(w, h, LP_LINEAR), weight(wgt), gravity(grav), margins(mgn), hasMargins_(true) {} LinearLayoutParams(Size w, Size h, const Margins &mgn) @@ -182,7 +182,7 @@ private: class LinearLayout : public ViewGroup { public: LinearLayout(Orientation orientation, LayoutParams *layoutParams = 0) - : ViewGroup(layoutParams), orientation_(orientation), defaultMargins_(0), spacing_(10) {} + : ViewGroup(layoutParams), orientation_(orientation), defaultMargins_(0) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; @@ -190,12 +190,13 @@ public: spacing_ = spacing; } std::string DescribeLog() const override { return (orientation_ == ORIENT_HORIZONTAL ? "LinearLayoutHoriz: " : "LinearLayoutVert: ") + View::DescribeLog(); } + Margins padding; protected: Orientation orientation_; private: Margins defaultMargins_; - float spacing_; + float spacing_ = 10.0f; }; class LinearLayoutList : public LinearLayout { @@ -247,7 +248,7 @@ public: private: GridLayoutSettings settings_; - int numColumns_; + int numColumns_ = 1; }; class GridLayoutList : public GridLayout { @@ -270,7 +271,7 @@ public: void Layout() override; bool Key(const KeyInput &input) override; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; std::string DescribeLog() const override { return "ScrollView: " + View::DescribeLog(); } @@ -293,6 +294,11 @@ public: void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override; void SetVisibility(Visibility visibility) override; + // If the view is smaller than the scroll view, sets whether to align to the bottom/right instead of the left. + void SetAlignOpposite(bool alignOpposite) { + alignOpposite_ = alignOpposite; + } + NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) override; private: @@ -310,16 +316,12 @@ private: float pull_ = 0.0f; float lastViewSize_ = 0.0f; float *rememberPos_ = nullptr; + bool alignOpposite_ = false; static float lastScrollPosX; static float lastScrollPosY; }; -class ViewPager : public ScrollView { -public: -}; - - class ChoiceStrip : public LinearLayout { public: ChoiceStrip(Orientation orientation, LayoutParams *layoutParams = 0); @@ -346,8 +348,8 @@ private: StickyChoice *Choice(int index); EventReturn OnChoiceClick(EventParams &e); - int selected_; - bool topTabs_; // Can be controlled with L/R. + int selected_ = 0; // Can be controlled with L/R. + bool topTabs_ = false; }; @@ -400,9 +402,9 @@ public: class ChoiceListAdaptor : public ListAdaptor { public: ChoiceListAdaptor(const char *items[], int numItems) : items_(items), numItems_(numItems) {} - virtual View *CreateItemView(int index); - virtual int GetNumItems() { return numItems_; } - virtual bool AddEventCallback(View *view, std::function callback); + View *CreateItemView(int index) override; + int GetNumItems() override { return numItems_; } + bool AddEventCallback(View *view, std::function callback) override; private: const char **items_; @@ -415,12 +417,12 @@ class StringVectorListAdaptor : public ListAdaptor { public: StringVectorListAdaptor() : selected_(-1) {} StringVectorListAdaptor(const std::vector &items, int selected = -1) : items_(items), selected_(selected) {} - virtual View *CreateItemView(int index) override; - virtual int GetNumItems() override { return (int)items_.size(); } - virtual bool AddEventCallback(View *view, std::function callback) override; + View *CreateItemView(int index) override; + int GetNumItems() override { return (int)items_.size(); } + bool AddEventCallback(View *view, std::function callback) override; void SetSelected(int sel) override { selected_ = sel; } - virtual std::string GetTitle(int index) const override { return items_[index]; } - virtual int GetSelected() override { return selected_; } + std::string GetTitle(int index) const override { return items_[index]; } + int GetSelected() override { return selected_; } private: std::vector items_; @@ -434,7 +436,7 @@ public: ListView(ListAdaptor *a, std::set hidden = std::set(), LayoutParams *layoutParams = 0); int GetSelected() { return adaptor_->GetSelected(); } - virtual void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; + void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; virtual void SetMaxHeight(float mh) { maxHeight_ = mh; } Event OnChoice; std::string DescribeLog() const override { return "ListView: " + View::DescribeLog(); } diff --git a/Common/VR/OpenXRLoader.cpp b/Common/VR/OpenXRLoader.cpp new file mode 100644 index 0000000000..4d5f8fb246 --- /dev/null +++ b/Common/VR/OpenXRLoader.cpp @@ -0,0 +1,160 @@ +#include "Common/VR/OpenXRLoader.h" +#ifdef _WIN32 +#include "Common/CommonWindows.h" +#endif + +#ifdef XR_NO_PROTOTYPES + +PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr; +PFN_xrEnumerateApiLayerProperties xrEnumerateApiLayerProperties; +PFN_xrEnumerateInstanceExtensionProperties xrEnumerateInstanceExtensionProperties; +PFN_xrCreateInstance xrCreateInstance; +PFN_xrDestroyInstance xrDestroyInstance; +PFN_xrGetInstanceProperties xrGetInstanceProperties; +PFN_xrPollEvent xrPollEvent; +PFN_xrResultToString xrResultToString; +PFN_xrStructureTypeToString xrStructureTypeToString; +PFN_xrGetSystem xrGetSystem; +PFN_xrGetSystemProperties xrGetSystemProperties; +PFN_xrEnumerateEnvironmentBlendModes xrEnumerateEnvironmentBlendModes; +PFN_xrCreateSession xrCreateSession; +PFN_xrDestroySession xrDestroySession; +PFN_xrEnumerateReferenceSpaces xrEnumerateReferenceSpaces; +PFN_xrCreateReferenceSpace xrCreateReferenceSpace; +PFN_xrGetReferenceSpaceBoundsRect xrGetReferenceSpaceBoundsRect; +PFN_xrCreateActionSpace xrCreateActionSpace; +PFN_xrLocateSpace xrLocateSpace; +PFN_xrDestroySpace xrDestroySpace; +PFN_xrEnumerateViewConfigurations xrEnumerateViewConfigurations; +PFN_xrGetViewConfigurationProperties xrGetViewConfigurationProperties; +PFN_xrEnumerateViewConfigurationViews xrEnumerateViewConfigurationViews; +PFN_xrEnumerateSwapchainFormats xrEnumerateSwapchainFormats; +PFN_xrCreateSwapchain xrCreateSwapchain; +PFN_xrDestroySwapchain xrDestroySwapchain; +PFN_xrEnumerateSwapchainImages xrEnumerateSwapchainImages; +PFN_xrAcquireSwapchainImage xrAcquireSwapchainImage; +PFN_xrWaitSwapchainImage xrWaitSwapchainImage; +PFN_xrReleaseSwapchainImage xrReleaseSwapchainImage; +PFN_xrBeginSession xrBeginSession; +PFN_xrEndSession xrEndSession; +PFN_xrRequestExitSession xrRequestExitSession; +PFN_xrWaitFrame xrWaitFrame; +PFN_xrBeginFrame xrBeginFrame; +PFN_xrEndFrame xrEndFrame; +PFN_xrLocateViews xrLocateViews; +PFN_xrStringToPath xrStringToPath; +PFN_xrPathToString xrPathToString; +PFN_xrCreateActionSet xrCreateActionSet; +PFN_xrDestroyActionSet xrDestroyActionSet; +PFN_xrCreateAction xrCreateAction; +PFN_xrDestroyAction xrDestroyAction; +PFN_xrSuggestInteractionProfileBindings xrSuggestInteractionProfileBindings; +PFN_xrAttachSessionActionSets xrAttachSessionActionSets; +PFN_xrGetCurrentInteractionProfile xrGetCurrentInteractionProfile; +PFN_xrGetActionStateBoolean xrGetActionStateBoolean; +PFN_xrGetActionStateFloat xrGetActionStateFloat; +PFN_xrGetActionStateVector2f xrGetActionStateVector2f; +PFN_xrGetActionStatePose xrGetActionStatePose; +PFN_xrSyncActions xrSyncActions; +PFN_xrEnumerateBoundSourcesForAction xrEnumerateBoundSourcesForAction; +PFN_xrGetInputSourceLocalizedName xrGetInputSourceLocalizedName; +PFN_xrApplyHapticFeedback xrApplyHapticFeedback; +PFN_xrStopHapticFeedback xrStopHapticFeedback; + +#ifdef XR_USE_PLATFORM_WIN32 +#define dlsym(x, y) GetProcAddress(x, y) +static HMODULE g_xrLibrary; +#else +#define dlsym(x, y) nullptr +void *g_xrLibrary; +#endif + +#define LOAD_INSTANCE_FUNC(name) (PFN_ ## name)xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction *)(&name)) + + +bool XRLoad() { + if (g_xrLibrary) { + // Already loaded. That's OK. + return true; + } + +#ifdef XR_USE_PLATFORM_WIN32 + g_xrLibrary = LoadLibrary(L"openxr_loader.dll"); + if (!g_xrLibrary) { + return false; + } +#else + return false; +#endif + + // Load the three basic functions. + xrGetInstanceProcAddr = (PFN_xrGetInstanceProcAddr)dlsym(g_xrLibrary, "xrGetInstanceProcAddr"); + xrEnumerateApiLayerProperties = (PFN_xrEnumerateApiLayerProperties)dlsym(g_xrLibrary, "xrEnumerateApiLayerProperties"); + xrEnumerateInstanceExtensionProperties = (PFN_xrEnumerateInstanceExtensionProperties)dlsym(g_xrLibrary, "xrEnumerateInstanceExtensionProperties"); + + // Load the rest. + return true; +} + +void XRLoadInstanceFunctions(XrInstance instance) { + LOAD_INSTANCE_FUNC(xrCreateInstance); + LOAD_INSTANCE_FUNC(xrGetInstanceProcAddr); + LOAD_INSTANCE_FUNC(xrEnumerateApiLayerProperties); + LOAD_INSTANCE_FUNC(xrEnumerateInstanceExtensionProperties); + LOAD_INSTANCE_FUNC(xrCreateInstance); + LOAD_INSTANCE_FUNC(xrDestroyInstance); + LOAD_INSTANCE_FUNC(xrGetInstanceProperties); + LOAD_INSTANCE_FUNC(xrPollEvent); + LOAD_INSTANCE_FUNC(xrResultToString); + LOAD_INSTANCE_FUNC(xrStructureTypeToString); + LOAD_INSTANCE_FUNC(xrGetSystem); + LOAD_INSTANCE_FUNC(xrGetSystemProperties); + LOAD_INSTANCE_FUNC(xrEnumerateEnvironmentBlendModes); + LOAD_INSTANCE_FUNC(xrCreateSession); + LOAD_INSTANCE_FUNC(xrDestroySession); + LOAD_INSTANCE_FUNC(xrEnumerateReferenceSpaces); + LOAD_INSTANCE_FUNC(xrCreateReferenceSpace); + LOAD_INSTANCE_FUNC(xrGetReferenceSpaceBoundsRect); + LOAD_INSTANCE_FUNC(xrCreateActionSpace); + LOAD_INSTANCE_FUNC(xrLocateSpace); + LOAD_INSTANCE_FUNC(xrDestroySpace); + LOAD_INSTANCE_FUNC(xrEnumerateViewConfigurations); + LOAD_INSTANCE_FUNC(xrGetViewConfigurationProperties); + LOAD_INSTANCE_FUNC(xrEnumerateViewConfigurationViews); + LOAD_INSTANCE_FUNC(xrEnumerateSwapchainFormats); + LOAD_INSTANCE_FUNC(xrCreateSwapchain); + LOAD_INSTANCE_FUNC(xrDestroySwapchain); + LOAD_INSTANCE_FUNC(xrEnumerateSwapchainImages); + LOAD_INSTANCE_FUNC(xrAcquireSwapchainImage); + LOAD_INSTANCE_FUNC(xrWaitSwapchainImage); + LOAD_INSTANCE_FUNC(xrReleaseSwapchainImage); + LOAD_INSTANCE_FUNC(xrBeginSession); + LOAD_INSTANCE_FUNC(xrEndSession); + LOAD_INSTANCE_FUNC(xrRequestExitSession); + LOAD_INSTANCE_FUNC(xrWaitFrame); + LOAD_INSTANCE_FUNC(xrBeginFrame); + LOAD_INSTANCE_FUNC(xrEndFrame); + LOAD_INSTANCE_FUNC(xrLocateViews); + LOAD_INSTANCE_FUNC(xrStringToPath); + LOAD_INSTANCE_FUNC(xrPathToString); + LOAD_INSTANCE_FUNC(xrCreateActionSet); + LOAD_INSTANCE_FUNC(xrDestroyActionSet); + LOAD_INSTANCE_FUNC(xrCreateAction); + LOAD_INSTANCE_FUNC(xrDestroyAction); + LOAD_INSTANCE_FUNC(xrSuggestInteractionProfileBindings); + LOAD_INSTANCE_FUNC(xrAttachSessionActionSets); + LOAD_INSTANCE_FUNC(xrGetCurrentInteractionProfile); + LOAD_INSTANCE_FUNC(xrGetActionStateBoolean); + LOAD_INSTANCE_FUNC(xrGetActionStateFloat); + LOAD_INSTANCE_FUNC(xrGetActionStateVector2f); + LOAD_INSTANCE_FUNC(xrGetActionStatePose); + LOAD_INSTANCE_FUNC(xrSyncActions); + LOAD_INSTANCE_FUNC(xrEnumerateBoundSourcesForAction); + LOAD_INSTANCE_FUNC(xrGetInputSourceLocalizedName); + LOAD_INSTANCE_FUNC(xrApplyHapticFeedback); + LOAD_INSTANCE_FUNC(xrStopHapticFeedback); + + // TODO: Load any extensions we need, too. +} + +#endif diff --git a/Common/VR/OpenXRLoader.h b/Common/VR/OpenXRLoader.h new file mode 100644 index 0000000000..ce6613ec5e --- /dev/null +++ b/Common/VR/OpenXRLoader.h @@ -0,0 +1,122 @@ +#pragma once + +//Vulkan +#ifdef VK_USE_NATIVE_LIB +#include +#else +#include "Common/GPU/Vulkan/VulkanLoader.h" +using namespace PPSSPP_VK; +#endif + +#ifdef ANDROID +#include +#define XR_USE_PLATFORM_ANDROID 1 +#define XR_USE_GRAPHICS_API_OPENGL_ES 1 +#define XR_USE_GRAPHICS_API_VULKAN 1 +#include +#include + +#if OPENXR +// One of the Android-based headsets. We're linking with a static OpenXR loader. +#else +// Normal Android app, we don't have a loader so use our own dynamic loader, which won't load anything. +#define XR_NO_PROTOTYPES 1 +#endif + +#elif defined(_WIN32) +#include "Common/CommonWindows.h" +#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP +#if defined(_M_IX86) || defined(_M_X64) +#include "Common/GPU/OpenGL/GLCommon.h" +#define XR_USE_GRAPHICS_API_OPENGL 1 +#endif +#define XR_USE_PLATFORM_WIN32 1 +#endif +#endif +#define XR_USE_GRAPHICS_API_VULKAN 1 +#include "Common/VR/OpenXRLoader.h" +#include +#define XR_NO_PROTOTYPES 1 +#else +#define XR_USE_GRAPHICS_API_VULKAN 1 +#define XR_NO_PROTOTYPES 1 +#endif + +#include +#include + +#ifdef XR_NO_PROTOTYPES + +extern PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr; +extern PFN_xrEnumerateApiLayerProperties xrEnumerateApiLayerProperties; +extern PFN_xrEnumerateInstanceExtensionProperties xrEnumerateInstanceExtensionProperties; +extern PFN_xrCreateInstance xrCreateInstance; +extern PFN_xrDestroyInstance xrDestroyInstance; +extern PFN_xrGetInstanceProperties xrGetInstanceProperties; +extern PFN_xrPollEvent xrPollEvent; +extern PFN_xrResultToString xrResultToString; +extern PFN_xrStructureTypeToString xrStructureTypeToString; +extern PFN_xrGetSystem xrGetSystem; +extern PFN_xrGetSystemProperties xrGetSystemProperties; +extern PFN_xrEnumerateEnvironmentBlendModes xrEnumerateEnvironmentBlendModes; +extern PFN_xrCreateSession xrCreateSession; +extern PFN_xrDestroySession xrDestroySession; +extern PFN_xrEnumerateReferenceSpaces xrEnumerateReferenceSpaces; +extern PFN_xrCreateReferenceSpace xrCreateReferenceSpace; +extern PFN_xrGetReferenceSpaceBoundsRect xrGetReferenceSpaceBoundsRect; +extern PFN_xrCreateActionSpace xrCreateActionSpace; +extern PFN_xrLocateSpace xrLocateSpace; +extern PFN_xrDestroySpace xrDestroySpace; +extern PFN_xrEnumerateViewConfigurations xrEnumerateViewConfigurations; +extern PFN_xrGetViewConfigurationProperties xrGetViewConfigurationProperties; +extern PFN_xrEnumerateViewConfigurationViews xrEnumerateViewConfigurationViews; +extern PFN_xrEnumerateSwapchainFormats xrEnumerateSwapchainFormats; +extern PFN_xrCreateSwapchain xrCreateSwapchain; +extern PFN_xrDestroySwapchain xrDestroySwapchain; +extern PFN_xrEnumerateSwapchainImages xrEnumerateSwapchainImages; +extern PFN_xrAcquireSwapchainImage xrAcquireSwapchainImage; +extern PFN_xrWaitSwapchainImage xrWaitSwapchainImage; +extern PFN_xrReleaseSwapchainImage xrReleaseSwapchainImage; +extern PFN_xrBeginSession xrBeginSession; +extern PFN_xrEndSession xrEndSession; +extern PFN_xrRequestExitSession xrRequestExitSession; +extern PFN_xrWaitFrame xrWaitFrame; +extern PFN_xrBeginFrame xrBeginFrame; +extern PFN_xrEndFrame xrEndFrame; +extern PFN_xrLocateViews xrLocateViews; +extern PFN_xrStringToPath xrStringToPath; +extern PFN_xrPathToString xrPathToString; +extern PFN_xrCreateActionSet xrCreateActionSet; +extern PFN_xrDestroyActionSet xrDestroyActionSet; +extern PFN_xrCreateAction xrCreateAction; +extern PFN_xrDestroyAction xrDestroyAction; +extern PFN_xrSuggestInteractionProfileBindings xrSuggestInteractionProfileBindings; +extern PFN_xrAttachSessionActionSets xrAttachSessionActionSets; +extern PFN_xrGetCurrentInteractionProfile xrGetCurrentInteractionProfile; +extern PFN_xrGetActionStateBoolean xrGetActionStateBoolean; +extern PFN_xrGetActionStateFloat xrGetActionStateFloat; +extern PFN_xrGetActionStateVector2f xrGetActionStateVector2f; +extern PFN_xrGetActionStatePose xrGetActionStatePose; +extern PFN_xrSyncActions xrSyncActions; +extern PFN_xrEnumerateBoundSourcesForAction xrEnumerateBoundSourcesForAction; +extern PFN_xrGetInputSourceLocalizedName xrGetInputSourceLocalizedName; +extern PFN_xrApplyHapticFeedback xrApplyHapticFeedback; +extern PFN_xrStopHapticFeedback xrStopHapticFeedback; + +// Dynamic loader for OpenXR on desktop platforms. +// On Quest/Pico, we use statically linked loaders provided by the platform owners. +// On Windows (and Linux etc), we're not so lucky - we could link to static libraries, but we really +// don't want to as we still want to function when one is not present. +// +// Similar to our dynamic Vulkan loader. + +bool XRLoad(); +void XRLoadInstanceFunctions(XrInstance instance); + +#else + +inline bool XRLoad() { return true; } +inline void XRLoadInstanceFunctions(XrInstance instance) {} + +#endif diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 9d1db94576..46dca63f4b 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -1,18 +1,54 @@ -#include "Common/GPU/OpenGL/GLRenderManager.h" - #include "Common/VR/PPSSPPVR.h" + #include "Common/VR/VRBase.h" +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES +#include "Common/GPU/OpenGL/GLRenderManager.h" +#endif + #include "Common/VR/VRInput.h" #include "Common/VR/VRMath.h" #include "Common/VR/VRRenderer.h" -#include "Common/VR/VRTweaks.h" + +#include "Common/GPU/Vulkan/VulkanContext.h" + +#include "Common/Math/lin/matrix4x4.h" #include "Core/HLE/sceDisplay.h" #include "Core/Config.h" #include "Core/KeyMap.h" #include "Core/System.h" +enum VRMatrix { + VR_PROJECTION_MATRIX, + VR_VIEW_MATRIX_LEFT_EYE, + VR_VIEW_MATRIX_RIGHT_EYE, + VR_MATRIX_COUNT +}; + +enum VRMirroring { + VR_MIRRORING_UPDATED, + VR_MIRRORING_AXIS_X, + VR_MIRRORING_AXIS_Y, + VR_MIRRORING_AXIS_Z, + VR_MIRRORING_PITCH, + VR_MIRRORING_YAW, + VR_MIRRORING_ROLL, + VR_MIRRORING_COUNT +}; + +static VRAppMode appMode = VR_MENU_MODE; +static std::map > pspAxis; +static std::map pspKeys; + +static int vr3DGeometryCount = 0; static long vrCompat[VR_COMPAT_MAX]; +static bool vrFlatGame = false; +static float vrMatrix[VR_MATRIX_COUNT][16]; +static bool vrMirroring[VR_MIRRORING_COUNT]; + +static bool(*NativeAxis)(const AxisInput &axis); +static bool(*NativeKey)(const KeyInput &key); +static bool(*NativeTouch)(const TouchInput &touch); /* ================================================================================ @@ -36,16 +72,6 @@ struct ButtonMapping { } }; -struct MouseActivator { - bool activate; - ovrButton ovr; - - MouseActivator(bool activate, ovrButton ovr) { - this->activate = activate; - this->ovr = ovr; - } -}; - static std::vector leftControllerMapping = { ButtonMapping(NKCODE_BUTTON_X, ovrButton_X), ButtonMapping(NKCODE_BUTTON_Y, ovrButton_Y), @@ -76,16 +102,15 @@ static std::vector controllerMapping[2] = { leftControllerMapping, rightControllerMapping }; -static int mouseController = -1; -static bool mousePressed[] = {false, false}; +static bool controllerMotion[2][5] = {}; +static int mouseController = 1; +static bool mousePressed = false; -static std::vector mouseActivators = { - MouseActivator(true, ovrButton_Trigger), - MouseActivator(false, ovrButton_Up), - MouseActivator(false, ovrButton_Down), - MouseActivator(false, ovrButton_Left), - MouseActivator(false, ovrButton_Right), -}; +inline float clampFloat(float x, float minValue, float maxValue) { + if (x < minValue) return minValue; + if (x > maxValue) return maxValue; + return x; +} /* ================================================================================ @@ -95,25 +120,65 @@ VR app flow integration ================================================================================ */ -bool IsVRBuild() { +bool IsVREnabled() { + // For now, let the OPENXR build flag control enablement. + // This will change. +#ifdef OPENXR return true; +#else + return false; +#endif } -void InitVROnAndroid(void* vm, void* activity, int version, const char* name) { +#if PPSSPP_PLATFORM(ANDROID) +void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name) { + + //Get device vendor (uppercase) + char vendor[64]; + sscanf(system, "%[^:]", vendor); + for (unsigned int i = 0; i < strlen(vendor); i++) { + if ((vendor[i] >= 'a') && (vendor[i] <= 'z')) { + vendor[i] = vendor[i] - 'a' + 'A'; + } + } + + //Set platform flags + if (strcmp(vendor, "PICO") == 0) { + VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true); + VR_SetPlatformFLag(VR_PLATFORM_INSTANCE_EXT, true); + } else if ((strcmp(vendor, "META") == 0) || (strcmp(vendor, "OCULUS") == 0)) { + VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); + VR_SetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT, true); + } + VR_SetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN, (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN); + + //Init VR ovrJava java; java.Vm = (JavaVM*)vm; java.ActivityObject = (jobject)activity; - java.AppVersion = version; - strcpy(java.AppName, name); - VR_Init(java); - - __DisplaySetFramerate(72); + VR_Init(&java, name, version); } +#endif -void EnterVR(bool firstStart) { +void EnterVR(bool firstStart, void* vulkanContext) { if (firstStart) { - VR_EnterVR(VR_GetEngine()); - IN_VRInit(VR_GetEngine()); + engine_t* engine = VR_GetEngine(); + bool useVulkan = (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN; + if (useVulkan) { + auto* context = (VulkanContext*)vulkanContext; + engine->graphicsBindingVulkan = {}; + engine->graphicsBindingVulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR; + engine->graphicsBindingVulkan.next = NULL; + engine->graphicsBindingVulkan.device = context->GetDevice(); + engine->graphicsBindingVulkan.instance = context->GetInstance(); + engine->graphicsBindingVulkan.physicalDevice = context->GetCurrentPhysicalDevice(); + engine->graphicsBindingVulkan.queueFamilyIndex = context->GetGraphicsQueueFamilyIndex(); + engine->graphicsBindingVulkan.queueIndex = 0; + VR_EnterVR(engine, &engine->graphicsBindingVulkan); + } else { + VR_EnterVR(engine, nullptr); + } + IN_VRInit(engine); } VR_SetConfig(VR_CONFIG_VIEWPORT_VALID, false); } @@ -124,17 +189,57 @@ void GetVRResolutionPerEye(int* width, int* height) { } } -void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) { +void SetVRCallbacks(bool(*axis)(const AxisInput &axis), bool(*key)(const KeyInput &key), bool(*touch)(const TouchInput &touch)) { + NativeAxis = axis; + NativeKey = key; + NativeTouch = touch; +} + +/* +================================================================================ + +VR input integration + +================================================================================ +*/ + +void SetVRAppMode(VRAppMode mode) { + appMode = mode; +} + +void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) { + //axis + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + AxisInput axis = {}; + for (int j = 0; j < 2; j++) { + XrVector2f joystick = IN_VRGetJoystickState(j); + axis.deviceId = DEVICE_ID_DEFAULT; + + //horizontal + axis.axisId = j == 0 ? JOYSTICK_AXIS_X : JOYSTICK_AXIS_Z; + axis.value = joystick.x; + NativeAxis(axis); + + //vertical + axis.axisId = j == 0 ? JOYSTICK_AXIS_Y : JOYSTICK_AXIS_RZ; + axis.value = -joystick.y; + NativeAxis(axis); + } + } + //buttons KeyInput keyInput = {}; for (int j = 0; j < 2; j++) { int status = IN_VRGetButtonState(j); for (ButtonMapping& m : controllerMapping[j]) { + + //fill KeyInput structure bool pressed = status & m.ovr; keyInput.flags = pressed ? KEY_DOWN : KEY_UP; keyInput.keyCode = m.keycode; keyInput.deviceId = controllerIds[j]; + //process the key action if (m.pressed != pressed) { if (pressed && haptics) { INVR_Vibrate(100, j, 1000); @@ -152,18 +257,104 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con } } + //motion control + if (g_Config.bEnableMotions) { + for (int j = 0; j < 2; j++) { + bool activate; + float limit = g_Config.fMotionLength; //length of needed movement in meters + XrVector3f axis = {0, 1, 0}; + float center = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_YAW)); + XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); + XrVector3f position = XrQuaternionf_Rotate(orientation, IN_VRGetPose(j).position); + + //up + activate = position.y > limit; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_UP; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][0] != activate) NativeKey(keyInput); + controllerMotion[j][0] = activate; + + //down + activate = position.y < -limit * 1.5f; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_DOWN; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][1] != activate) NativeKey(keyInput); + controllerMotion[j][1] = activate; + + //left + activate = position.x < -limit * (j == 0 ? 1.0f : 0.25f); + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_LEFT; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][2] != activate) NativeKey(keyInput); + controllerMotion[j][2] = activate; + + //right + activate = position.x > limit * (j == 1 ? 1.0f : 0.25f); + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_RIGHT; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][3] != activate) NativeKey(keyInput); + controllerMotion[j][3] = activate; + + //forward + activate = position.z < -limit; + keyInput.flags = activate ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOTION_FORWARD; + keyInput.deviceId = controllerIds[j]; + if (controllerMotion[j][4] != activate) NativeKey(keyInput); + controllerMotion[j][4] = activate; + } + } + + // Camera adjust + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + for (auto& device : pspAxis) { + for (auto& axis : device.second) { + switch(axis.first) { + case JOYSTICK_AXIS_X: + if (axis.second < -0.75f) g_Config.fCameraSide -= 0.05f; + if (axis.second > 0.75f) g_Config.fCameraSide += 0.05f; + g_Config.fCameraSide = clampFloat(g_Config.fCameraSide, -50.0f, 50.0f); + break; + case JOYSTICK_AXIS_Y: + if (axis.second > 0.75f) g_Config.fCameraHeight -= 0.05f; + if (axis.second < -0.75f) g_Config.fCameraHeight += 0.05f; + g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -50.0f, 50.0f); + break; + case JOYSTICK_AXIS_Z: + if (axis.second < -0.75f) g_Config.fHeadUpDisplayScale -= 0.01f; + if (axis.second > 0.75f) g_Config.fHeadUpDisplayScale += 0.01f; + g_Config.fHeadUpDisplayScale = clampFloat(g_Config.fHeadUpDisplayScale, 0.2f, 1.5f); + break; + case JOYSTICK_AXIS_RZ: + if (axis.second > 0.75f) g_Config.fCameraDistance -= 0.1f; + if (axis.second < -0.75f) g_Config.fCameraDistance += 0.1f; + g_Config.fCameraDistance = clampFloat(g_Config.fCameraDistance, -50.0f, 50.0f); + break; + } + } + } + } + //enable or disable mouse for (int j = 0; j < 2; j++) { - int status = IN_VRGetButtonState(j); - for (MouseActivator& m : mouseActivators) { - if (status & m.ovr) { - mouseController = m.activate ? j : -1; + bool pressed = IN_VRGetButtonState(j) & ovrButton_Trigger; + if (pressed) { + int lastController = mouseController; + mouseController = j; + + //prevent misclicks when changing the left/right controller + if (lastController != mouseController) { + mousePressed = true; } } } //mouse cursor - if (mouseController >= 0) { + if ((mouseController >= 0) && ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE))) { //get position on screen XrPosef pose = IN_VRGetPose(mouseController); XrVector3f angles = XrQuaternionf_ToEulerAngles(pose.orientation); @@ -172,43 +363,104 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(con float cx = width / 2; float cy = height / 2; float speed = (cx + cy) / 2; - float x = cx - tan(ToRadians(angles.y - (float)VR_GetConfig(VR_CONFIG_MENU_YAW))) * speed; - float y = cy - tan(ToRadians(angles.x)) * speed; + float x = cx - tan(ToRadians(angles.y - VR_GetConfigFloat(VR_CONFIG_MENU_YAW))) * speed; + float y = cy - tan(ToRadians(angles.x)) * speed * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); //set renderer VR_SetConfig(VR_CONFIG_MOUSE_X, (int)x); VR_SetConfig(VR_CONFIG_MOUSE_Y, (int)y); - VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 6 * (int)pow(VR_GetConfig(VR_CONFIG_CANVAS_DISTANCE), 0.25f)); + VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 6 * (int)pow(VR_GetConfigFloat(VR_CONFIG_CANVAS_DISTANCE), 0.25f)); //inform engine about the status TouchInput touch; touch.id = mouseController; touch.x = x * dp_xscale; - touch.y = (height - y - 1) * dp_yscale; + touch.y = (height - y - 1) * dp_yscale / VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); bool pressed = IN_VRGetButtonState(mouseController) & ovrButton_Trigger; - if (mousePressed[mouseController] != pressed) { - if (!pressed) { + if (mousePressed != pressed) { + if (pressed) { touch.flags = TOUCH_DOWN; NativeTouch(touch); touch.flags = TOUCH_UP; NativeTouch(touch); } - mousePressed[mouseController] = pressed; + mousePressed = pressed; + } + + //mouse wheel emulation + for (int j = 0; j < 2; j++) { + keyInput.deviceId = controllerIds[j]; + float scroll = -IN_VRGetJoystickState(j).y; + keyInput.flags = scroll < -0.5f ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_UP; + NativeKey(keyInput); + keyInput.flags = scroll > 0.5f ? KEY_DOWN : KEY_UP; + keyInput.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN; + NativeKey(keyInput); } } else { VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 0); } } -void UpdateVRScreenKey(const KeyInput &key) { +bool UpdateVRAxis(const AxisInput &axis) { + if (pspAxis.find(axis.deviceId) == pspAxis.end()) { + pspAxis[axis.deviceId] = std::map(); + } + pspAxis[axis.deviceId][axis.axisId] = axis.value; + return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; +} + +bool UpdateVRKeys(const KeyInput &key) { + //store key value std::vector nativeKeys; + bool wasCameraAdjustOn = pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &nativeKeys)) { for (int& nativeKey : nativeKeys) { - if (nativeKey == CTRL_SCREEN) { - VR_SetConfig(VR_CONFIG_FORCE_2D, key.flags & KEY_DOWN); + pspKeys[nativeKey] = key.flags & KEY_DOWN; + } + } + + //block VR controller keys in the UI mode + if ((key.deviceId == controllerIds[0]) || (key.deviceId == controllerIds[1])) { + if ((appMode == VR_DIALOG_MODE) || (appMode == VR_MENU_MODE)) { + switch (key.keyCode) { + case NKCODE_BACK: + case NKCODE_EXT_MOUSEWHEEL_UP: + case NKCODE_EXT_MOUSEWHEEL_DOWN: + return true; + default: + return false; } } } + + // Release keys on enabling camera adjust + if (!wasCameraAdjustOn && pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { + KeyInput keyUp; + keyUp.deviceId = key.deviceId; + keyUp.flags = KEY_UP; + + pspKeys[VIRTKEY_VR_CAMERA_ADJUST] = false; + for (auto& pspKey : pspKeys) { + if (pspKey.second) { + keyUp.keyCode = pspKey.first; + NativeKey(keyUp); + } + } + pspKeys[VIRTKEY_VR_CAMERA_ADJUST] = true; + } + + // Reset camera adjust + if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST] && pspKeys[VIRTKEY_VR_CAMERA_RESET]) { + g_Config.fCameraHeight = 0; + g_Config.fCameraSide = 0; + g_Config.fCameraDistance = 0; + g_Config.fHeadUpDisplayScale = 0.3f; + } + + //block keys by camera adjust + return !pspKeys[VIRTKEY_VR_CAMERA_ADJUST]; } /* @@ -219,6 +471,8 @@ void UpdateVRScreenKey(const KeyInput &key) { ================================================================================ */ +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES + void PreprocessSkyplane(GLRStep* step) { // Do not do anything if the scene is not in VR. @@ -260,6 +514,12 @@ void PreprocessStepVR(void* step) { if (vrCompat[VR_COMPAT_SKYPLANE]) PreprocessSkyplane(glrStep); } +#else + +void PreprocessStepVR(void* step) {} + +#endif + void SetVRCompat(VRCompatFlag flag, long value) { vrCompat[flag] = value; } @@ -272,8 +532,8 @@ VR rendering integration ================================================================================ */ -void BindVRFramebuffer() { - VR_BindFramebuffer(VR_GetEngine()); +void* BindVRFramebuffer() { + return VR_BindFramebuffer(VR_GetEngine()); } bool StartVRRender() { @@ -284,22 +544,152 @@ bool StartVRRender() { if (VR_InitFrame(VR_GetEngine())) { - // Decide if the scene is 3D or not - if (g_Config.bEnableVR && !VR_GetConfig(VR_CONFIG_FORCE_2D) && (VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) > 15)) { - bool stereo = VR_GetConfig(VR_CONFIG_6DOF_PRECISE) && g_Config.bEnableStereo; - VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); - } else { - VR_SetConfig(VR_CONFIG_MODE, VR_MODE_FLAT_SCREEN); + // Get OpenXR view and fov + XrFovf fov = {}; + XrPosef invViewTransform[2]; + for (int eye = 0; eye < ovrMaxNumEyes; eye++) { + XrView view = VR_GetView(eye); + fov.angleLeft += view.fov.angleLeft / 2.0f; + fov.angleRight += view.fov.angleRight / 2.0f; + fov.angleUp += view.fov.angleUp / 2.0f; + fov.angleDown += view.fov.angleDown / 2.0f; + invViewTransform[eye] = view.pose; } - VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) / 2); + + // Get 6DoF scale + float scale = 1.0f; + bool hasUnitScale = false; + if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { + scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; + hasUnitScale = true; + } + + // Update matrices + for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { + if (matrix == VR_PROJECTION_MATRIX) { + float nearZ = g_Config.fFieldOfViewPercentage / 200.0f; + float tanAngleLeft = tanf(fov.angleLeft); + float tanAngleRight = tanf(fov.angleRight); + float tanAngleDown = tanf(fov.angleDown); + float tanAngleUp = tanf(fov.angleUp); + + float M[16] = {}; + M[0] = 2 / (tanAngleRight - tanAngleLeft); + M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); + M[5] = 2 / (tanAngleUp - tanAngleDown); + M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); + M[10] = -1; + M[11] = -(nearZ + nearZ); + M[14] = -1; + + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); + } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + bool flatScreen = false; + XrPosef invView = invViewTransform[0]; + int vrMode = VR_GetConfig(VR_CONFIG_MODE); + if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { + invView = XrPosef_Identity(); + flatScreen = true; + } + + // get axis mirroring configuration + float mx = vrMirroring[VR_MIRRORING_PITCH] ? -1.0f : 1.0f; + float my = vrMirroring[VR_MIRRORING_YAW] ? -1.0f : 1.0f; + float mz = vrMirroring[VR_MIRRORING_ROLL] ? -1.0f : 1.0f; + + // ensure there is maximally one axis to mirror rotation + if (mx + my + mz < 0) { + mx *= -1.0f; + my *= -1.0f; + mz *= -1.0f; + } else { + invView = XrPosef_Inverse(invView); + } + + // create updated quaternion + XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); + XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); + XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); + XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); + invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); + + float M[16]; + XrQuaternionf_ToMatrix4f(&invView.orientation, M); + memcpy(&M, M, sizeof(float) * 16); + + // Apply 6Dof head movement + if (!flatScreen && g_Config.bEnable6DoF) { + M[3] -= invViewTransform[0].position.x * (vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f) * scale; + M[7] -= invViewTransform[0].position.y * (vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f) * scale; + M[11] -= invViewTransform[0].position.z * (vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f) * scale; + } + // Camera adjust - distance + if (fabsf(g_Config.fCameraDistance) > 0.0f) { + XrVector3f forward = {0.0f, 0.0f, g_Config.fCameraDistance * scale}; + forward = XrQuaternionf_Rotate(invView.orientation, forward); + forward = XrVector3f_ScalarMultiply(forward, vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f); + M[3] += forward.x; + M[7] += forward.y; + M[11] += forward.z; + } + // Camera adjust - height + if (fabsf(g_Config.fCameraHeight) > 0.0f) { + XrVector3f up = {0.0f, -g_Config.fCameraHeight * scale, 0.0f}; + up = XrQuaternionf_Rotate(invView.orientation, up); + up = XrVector3f_ScalarMultiply(up, vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f); + M[3] += up.x; + M[7] += up.y; + M[11] += up.z; + } + // Camera adjust - side + if (fabsf(g_Config.fCameraSide) > 0.0f) { + XrVector3f side = {-g_Config.fCameraSide * scale, 0.0f, 0.0f}; + side = XrQuaternionf_Rotate(invView.orientation, side); + side = XrVector3f_ScalarMultiply(side, vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f); + M[3] += side.x; + M[7] += side.y; + M[11] += side.z; + } + // Stereoscopy + if (hasUnitScale && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); + float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); + float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); + float ipd = sqrt(dx * dx + dy * dy + dz * dz); + XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; + separation = XrQuaternionf_Rotate(invView.orientation, separation); + separation = XrVector3f_ScalarMultiply(separation, vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f); + M[3] -= separation.x; + M[7] -= separation.y; + M[11] -= separation.z; + } + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); + } else { + assert(false); + } + } + + // Decide if the scene is 3D or not + bool stereo = hasUnitScale && g_Config.bEnableStereo; + VR_SetConfigFloat(VR_CONFIG_CANVAS_ASPECT, 480.0f / 272.0f); + if (g_Config.bEnableVR && !pspKeys[CTRL_SCREEN] && (appMode == VR_GAME_MODE) && (vr3DGeometryCount > 15)) { + VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); + vrFlatGame = false; + } else { + VR_SetConfig(VR_CONFIG_MODE, stereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); + if (IsGameVRScene()) { + vrFlatGame = true; + } + } + vr3DGeometryCount /= 2; // Set compatibility vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; // Set customizations - VR_SetConfig(VR_CONFIG_6DOF_ENABLED, g_Config.bEnable6DoF); - VR_SetConfig(VR_CONFIG_CANVAS_DISTANCE, g_Config.iCanvasDistance); - VR_SetConfig(VR_CONFIG_FOV_SCALE, g_Config.iFieldOfViewPercentage); + __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); + VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); + vrMirroring[VR_MIRRORING_UPDATED] = false; return true; } return false; @@ -322,43 +712,137 @@ int GetVRFBOIndex() { return VR_GetConfig(VR_CONFIG_CURRENT_FBO); } +int GetVRPassesCount() { + if (!IsMultiviewSupported() && g_Config.bEnableStereo) { + return 2; + } else { + return 1; + } +} + bool IsMultiviewSupported() { return false; } +bool IsFlatVRGame() { + return vrFlatGame; +} + bool IsFlatVRScene() { - return VR_GetConfig(VR_CONFIG_MODE) == VR_MODE_FLAT_SCREEN; + int vrMode = VR_GetConfig(VR_CONFIG_MODE); + return (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); +} + +bool IsGameVRScene() { + return (appMode == VR_GAME_MODE) || (appMode == VR_DIALOG_MODE); } bool Is2DVRObject(float* projMatrix, bool ortho) { - bool is2D = VR_TweakIsMatrixBigScale(projMatrix) || - VR_TweakIsMatrixIdentity(projMatrix) || - VR_TweakIsMatrixOneOrtho(projMatrix) || - VR_TweakIsMatrixOneScale(projMatrix) || - VR_TweakIsMatrixOneTransform(projMatrix); - if (!is2D && !ortho) { - VR_SetConfig(VR_CONFIG_3D_GEOMETRY_COUNT, VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) + 1); + + // Quick analyze if the object is in 2D + if ((fabs(fabs(projMatrix[12]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[13]) - 1.0f) < EPSILON) && (fabs(fabs(projMatrix[14]) - 1.0f) < EPSILON)) { + return true; + } else if ((fabs(projMatrix[0]) > 10.0f) && (fabs(projMatrix[5]) > 10.0f)) { + return true; + } else if (fabs(projMatrix[15] - 1) < EPSILON) { + return true; + } + + // Update 3D geometry count + bool identity = IsMatrixIdentity(projMatrix); + if (!identity && !ortho) { + vr3DGeometryCount++; + } + return identity || ortho; +} + +void UpdateVRParams(float* projMatrix, float* viewMatrix) { + + // Set mirroring of axes + bool identityView = PSP_CoreParameter().compat.vrCompat().IdentityViewHack && IsMatrixIdentity(viewMatrix); + if (!vrMirroring[VR_MIRRORING_UPDATED] && !IsMatrixIdentity(projMatrix) && !identityView) { + vrMirroring[VR_MIRRORING_UPDATED] = true; + vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0; + vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0; + vrMirroring[VR_MIRRORING_AXIS_Z] = projMatrix[10] > 0; + + float up = 0; + for (int i = 4; i < 7; i++) { + up += viewMatrix[i]; + } + + int variant = projMatrix[0] < 0; + variant += (projMatrix[5] < 0) << 1; + variant += (projMatrix[10] < 0) << 2; + variant += (up < 0) << 3; + + switch (variant) { + case 0: //e.g. ATV + case 1: //untested + vrMirroring[VR_MIRRORING_PITCH] = false; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = true; + break; + case 2: //e.g.PES 2014 + case 3: //untested + case 5: //e.g Dante's Inferno + case 7: //untested + case 8: //untested + case 9: //untested + case 10: //untested + case 11: //untested + case 13: //untested + case 15: //untested + vrMirroring[VR_MIRRORING_PITCH] = true; + vrMirroring[VR_MIRRORING_YAW] = true; + vrMirroring[VR_MIRRORING_ROLL] = false; + break; + case 4: //e.g. Assassins Creed + case 6: //e.g. Ghost in the shell + case 12: //e.g. GTA Vice City + case 14: //untested + vrMirroring[VR_MIRRORING_PITCH] = true; + vrMirroring[VR_MIRRORING_YAW] = false; + vrMirroring[VR_MIRRORING_ROLL] = true; + break; + default: + assert(false); + std::exit(1); + } } - return is2D; } void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { - VR_TweakProjection(projMatrix, leftEye, VR_PROJECTION_MATRIX_LEFT_EYE); - VR_TweakProjection(projMatrix, rightEye, VR_PROJECTION_MATRIX_RIGHT_EYE); - VR_TweakMirroring(projMatrix); - - // Set 6DoF scale - float scale = pow(fabs(projMatrix[14]), 1.15f); - if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { - scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; - VR_SetConfig(VR_CONFIG_6DOF_PRECISE, true); - } else { - VR_SetConfig(VR_CONFIG_6DOF_PRECISE, false); + float* hmdProjection = vrMatrix[VR_PROJECTION_MATRIX]; + for (int i = 0; i < 16; i++) { + if ((hmdProjection[i] > 0) != (projMatrix[i] > 0)) { + hmdProjection[i] *= -1.0f; + } } - VR_SetConfig(VR_CONFIG_6DOF_SCALE, (int)(scale * 1000000)); + memcpy(leftEye, hmdProjection, 16 * sizeof(float)); + memcpy(rightEye, hmdProjection, 16 * sizeof(float)); } void UpdateVRView(float* leftEye, float* rightEye) { - VR_TweakView(leftEye, VR_VIEW_MATRIX_LEFT_EYE); - VR_TweakView(rightEye, VR_VIEW_MATRIX_RIGHT_EYE); + float* dst[] = {leftEye, rightEye}; + float* matrix[] = {vrMatrix[VR_VIEW_MATRIX_LEFT_EYE], vrMatrix[VR_VIEW_MATRIX_RIGHT_EYE]}; + for (int index = 0; index < 2; index++) { + + // Validate the view matrix + if (PSP_CoreParameter().compat.vrCompat().IdentityViewHack && IsMatrixIdentity(dst[index])) { + return; + } + + // Get view matrix from the game + Lin::Matrix4x4 gameView = {}; + memcpy(gameView.m, dst[index], 16 * sizeof(float)); + + // Get view matrix from the headset + Lin::Matrix4x4 hmdView = {}; + memcpy(hmdView.m, matrix[index], 16 * sizeof(float)); + + // Combine the matrices + Lin::Matrix4x4 renderView = hmdView * gameView; + memcpy(dst[index], renderView.m, 16 * sizeof(float)); + } } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index fe6f7c4e98..009726a948 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -17,58 +17,43 @@ enum VRCompatFlag { VR_COMPAT_MAX }; -#ifdef OPENXR +enum VRAppMode { + VR_CONTROLLER_MAPPING_MODE, + VR_DIALOG_MODE, + VR_GAME_MODE, + VR_MENU_MODE, +}; // VR app flow integration -bool IsVRBuild(); -void InitVROnAndroid(void* vm, void* activity, int version, const char* name); -void EnterVR(bool firstStart); +bool IsVREnabled(); +void InitVROnAndroid(void* vm, void* activity, const char* system, int version, const char* name); +void EnterVR(bool firstStart, void* vulkanContext); void GetVRResolutionPerEye(int* width, int* height); -void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale); -void UpdateVRScreenKey(const KeyInput &key); +void SetVRCallbacks(bool(*axis)(const AxisInput &axis), bool(*key)(const KeyInput &key), bool(*touch)(const TouchInput &touch)); + +// VR input integration +void SetVRAppMode(VRAppMode mode); +void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale); +bool UpdateVRAxis(const AxisInput &axis); +bool UpdateVRKeys(const KeyInput &key); // VR games compatibility void PreprocessStepVR(void* step); void SetVRCompat(VRCompatFlag flag, long value); // VR rendering integration -void BindVRFramebuffer(); +void* BindVRFramebuffer(); bool StartVRRender(); void FinishVRRender(); void PreVRFrameRender(int fboIndex); void PostVRFrameRender(); int GetVRFBOIndex(); +int GetVRPassesCount(); bool IsMultiviewSupported(); +bool IsFlatVRGame(); bool IsFlatVRScene(); +bool IsGameVRScene(); bool Is2DVRObject(float* projMatrix, bool ortho); +void UpdateVRParams(float* projMatrix, float* viewMatrix); void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye); void UpdateVRView(float* leftEye, float* rightEye); - -#else //dummy integration - -// VR app flow integration -inline bool IsVRBuild() { return false; } -inline void InitVROnAndroid(void* vm, void* activity, int version, const char* name) {} -inline void EnterVR(bool firstTime) {} -inline void GetVRResolutionPerEye(int* width, int* height) {} -inline void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {} -inline void UpdateVRScreenKey(const KeyInput &key) {} - -// VR games compatibility -inline void PreprocessStepVR(void* step) {} -inline void SetVRCompat(VRCompatFlag flag, long value) {} - -// VR rendering integration -inline void BindVRFramebuffer() {} -inline bool StartVRRender() { return false; } -inline void FinishVRRender() {} -inline void PreVRFrameRender(int fboIndex) {} -inline void PostVRFrameRender() {} -inline int GetVRFBOIndex() { return 0; } -inline bool IsMultiviewSupported() { return false; } -inline bool IsFlatVRScene() { return true; } -inline bool Is2DVRObject(float* projMatrix, bool ortho) { return false; } -inline void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) {} -inline void UpdateVRView(float* leftEye, float* rightEye) {} - -#endif diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 4bc4723a11..2cb2d0557d 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -3,104 +3,89 @@ #include #include #include +#include + +#ifndef _WIN32 #include - -#ifdef OPENXR_PLATFORM_PICO -enum ConfigsSetEXT { - UNREAL_VERSION = 0, - TRACKING_ORIGIN, - OPENGL_NOERROR, - ENABLE_SIX_DOF, - PRESENTATION_FLAG, - ENABLE_CPT, - PLATFORM, - FOVEATION_LEVEL, - SET_DISPLAY_RATE = 8, - MRC_TEXTURE_ID = 9, -}; - -enum PxrTrackingDof { - PXR_TRACKING_3DOF = 0, - PXR_TRACKING_6DOF = 1 -}; - -typedef XrResult (XRAPI_PTR *PFN_xrSetEngineVersionPico)(XrInstance instance,const char* version); -typedef XrResult (XRAPI_PTR *PFN_xrStartCVControllerThreadPico)(XrInstance instance,int headSensorState, int handSensorState); -typedef XrResult (XRAPI_PTR *PFN_xrStopCVControllerThreadPico)(XrInstance instance,int headSensorState, int handSensorState); -typedef XrResult (XRAPI_PTR *PFN_xrSetConfigPICO) (XrSession instance, enum ConfigsSetEXT configIndex, char* configData); - -PFN_xrSetConfigPICO pfnXrSetConfigPICO = nullptr; -PFN_xrSetEngineVersionPico pfnXrSetEngineVersionPico = nullptr; -PFN_xrStartCVControllerThreadPico pfnXrStartCVControllerThreadPico = nullptr; -PFN_xrStopCVControllerThreadPico pfnXrStopCVControllerThreadPico = nullptr; #endif +static bool vr_platform[VR_PLATFORM_MAX]; static engine_t vr_engine; int vr_initialized = 0; -const char* const requiredExtensionNames[] = { - XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME, -#ifdef OPENXR_HAS_PERFORMANCE_EXTENSION - XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME, - XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME, -#endif -#ifdef OPENXR_PLATFORM_PICO - XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME, - "XR_PICO_android_controller_function_ext_enable", - "XR_PICO_view_state_ext_enable", - "XR_PICO_frame_end_info_ext", - "XR_PICO_configs_ext", - "XR_PICO_reset_sensor", -#endif - XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME}; -const uint32_t numRequiredExtensions = - sizeof(requiredExtensionNames) / sizeof(requiredExtensionNames[0]); - -void VR_Init( ovrJava java ) { +void VR_Init( void* system, const char* name, int version ) { if (vr_initialized) return; + if (!XRLoad()) { + return; + } + ovrApp_Clear(&vr_engine.appState); +#ifdef ANDROID PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR; - xrGetInstanceProcAddr( - XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR); + xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR); if (xrInitializeLoaderKHR != NULL) { - XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid; - memset(&loaderInitializeInfoAndroid, 0, sizeof(loaderInitializeInfoAndroid)); - loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR; - loaderInitializeInfoAndroid.next = NULL; - loaderInitializeInfoAndroid.applicationVM = java.Vm; - loaderInitializeInfoAndroid.applicationContext = java.ActivityObject; - xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid); + ovrJava* java = (ovrJava*)system; + XrLoaderInitInfoAndroidKHR loaderInitializeInfo; + memset(&loaderInitializeInfo, 0, sizeof(loaderInitializeInfo)); + loaderInitializeInfo.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR; + loaderInitializeInfo.next = NULL; + loaderInitializeInfo.applicationVM = java->Vm; + loaderInitializeInfo.applicationContext = java->ActivityObject; + xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfo); } +#endif + + std::vector extensions; + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + extensions.push_back(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME); + } else { +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + extensions.push_back(XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME); +#endif + } + extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); +#ifdef ANDROID + if (VR_GetPlatformFlag(VR_PLATFORM_INSTANCE_EXT)) { + extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); + } + if (VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) { + extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); + extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); + } +#endif // Create the OpenXR instance. XrApplicationInfo appInfo; memset(&appInfo, 0, sizeof(appInfo)); - strcpy(appInfo.applicationName, java.AppName); - strcpy(appInfo.engineName, java.AppName); - appInfo.applicationVersion = java.AppVersion; - appInfo.engineVersion = java.AppVersion; + strcpy(appInfo.applicationName, name); + strcpy(appInfo.engineName, name); + appInfo.applicationVersion = version; + appInfo.engineVersion = version; appInfo.apiVersion = XR_CURRENT_API_VERSION; XrInstanceCreateInfo instanceCreateInfo; memset(&instanceCreateInfo, 0, sizeof(instanceCreateInfo)); instanceCreateInfo.type = XR_TYPE_INSTANCE_CREATE_INFO; -#ifdef OPENXR_PLATFORM_PICO - XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; - instanceCreateInfoAndroid.applicationVM = java.Vm; - instanceCreateInfoAndroid.applicationActivity = java.ActivityObject; - instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; -#else instanceCreateInfo.next = NULL; -#endif instanceCreateInfo.createFlags = 0; instanceCreateInfo.applicationInfo = appInfo; instanceCreateInfo.enabledApiLayerCount = 0; instanceCreateInfo.enabledApiLayerNames = NULL; - instanceCreateInfo.enabledExtensionCount = numRequiredExtensions; - instanceCreateInfo.enabledExtensionNames = requiredExtensionNames; + instanceCreateInfo.enabledExtensionCount = (uint32_t)extensions.size(); + instanceCreateInfo.enabledExtensionNames = extensions.data(); + +#ifdef ANDROID + XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR}; + if (VR_GetPlatformFlag(VR_PLATFORM_INSTANCE_EXT)) { + ovrJava* java = (ovrJava*)system; + instanceCreateInfoAndroid.applicationVM = java->Vm; + instanceCreateInfoAndroid.applicationActivity = java->ActivityObject; + instanceCreateInfo.next = (XrBaseInStructure*)&instanceCreateInfoAndroid; + } +#endif XrResult initResult; OXR(initResult = xrCreateInstance(&instanceCreateInfo, &vr_engine.appState.Instance)); @@ -109,14 +94,7 @@ void VR_Init( ovrJava java ) { exit(1); } -#ifdef OPENXR_PLATFORM_PICO - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrSetEngineVersionPico", (PFN_xrVoidFunction*)(&pfnXrSetEngineVersionPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStartCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStartCVControllerThreadPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance, "xrStopCVControllerThreadPico", (PFN_xrVoidFunction*)(&pfnXrStopCVControllerThreadPico)); - xrGetInstanceProcAddr(vr_engine.appState.Instance,"xrSetConfigPICO", (PFN_xrVoidFunction*)(&pfnXrSetConfigPICO)); - if (pfnXrSetEngineVersionPico != nullptr) pfnXrSetEngineVersionPico(vr_engine.appState.Instance, "2.8.0.1"); - if (pfnXrStartCVControllerThreadPico != nullptr) pfnXrStartCVControllerThreadPico(vr_engine.appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); -#endif + XRLoadInstanceFunctions(vr_engine.appState.Instance); XrInstanceProperties instanceInfo; instanceInfo.type = XR_TYPE_INSTANCE_PROPERTIES; @@ -143,36 +121,45 @@ void VR_Init( ovrJava java ) { } // Get the graphics requirements. - PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL; - OXR(xrGetInstanceProcAddr( - vr_engine.appState.Instance, - "xrGetOpenGLESGraphicsRequirementsKHR", - (PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR))); + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + PFN_xrGetVulkanGraphicsRequirementsKHR pfnGetVulkanGraphicsRequirementsKHR = NULL; + OXR(xrGetInstanceProcAddr( + vr_engine.appState.Instance, + "xrGetVulkanGraphicsRequirementsKHR", + (PFN_xrVoidFunction*)(&pfnGetVulkanGraphicsRequirementsKHR))); - XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {}; - graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; - OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); + XrGraphicsRequirementsVulkanKHR graphicsRequirements = {}; + graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR; + OXR(pfnGetVulkanGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); + } else { +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL; + OXR(xrGetInstanceProcAddr( + vr_engine.appState.Instance, + "xrGetOpenGLESGraphicsRequirementsKHR", + (PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR))); + XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {}; + graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; + OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements)); +#endif + } + +#ifdef ANDROID vr_engine.appState.MainThreadTid = gettid(); +#endif vr_engine.appState.SystemId = systemId; - - vr_engine.java = java; vr_initialized = 1; } void VR_Destroy( engine_t* engine ) { if (engine == &vr_engine) { -#ifdef OPENXR_PLATFORM_PICO - if (pfnXrStopCVControllerThreadPico != nullptr) { - pfnXrStopCVControllerThreadPico(engine->appState.Instance, PXR_TRACKING_6DOF, PXR_TRACKING_6DOF); - } -#endif xrDestroyInstance(engine->appState.Instance); ovrApp_Destroy(&engine->appState); } } -void VR_EnterVR( engine_t* engine ) { +void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ) { if (engine->appState.Session) { ALOGE("VR_EnterVR called with existing session"); @@ -180,17 +167,28 @@ void VR_EnterVR( engine_t* engine ) { } // Create the OpenXR Session. - XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingAndroidGLES = {}; - graphicsBindingAndroidGLES.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; - graphicsBindingAndroidGLES.next = NULL; - graphicsBindingAndroidGLES.display = eglGetCurrentDisplay(); - graphicsBindingAndroidGLES.config = eglGetCurrentSurface(EGL_DRAW); - graphicsBindingAndroidGLES.context = eglGetCurrentContext(); - XrSessionCreateInfo sessionCreateInfo = {}; +#ifdef ANDROID + XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingGL = {}; +#elif XR_USE_GRAPHICS_API_OPENGL + XrGraphicsBindingOpenGLWin32KHR graphicsBindingGL = {}; +#endif memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo)); + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + sessionCreateInfo.next = graphicsBindingVulkan; + } else { +#ifdef ANDROID + graphicsBindingGL.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; + graphicsBindingGL.next = NULL; + graphicsBindingGL.display = eglGetCurrentDisplay(); + graphicsBindingGL.config = eglGetCurrentSurface(EGL_DRAW); + graphicsBindingGL.context = eglGetCurrentContext(); + sessionCreateInfo.next = &graphicsBindingGL; +#else + //TODO:PCVR definition +#endif + } sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO; - sessionCreateInfo.next = &graphicsBindingAndroidGLES; sessionCreateInfo.createFlags = 0; sessionCreateInfo.systemId = engine->appState.SystemId; @@ -200,9 +198,6 @@ void VR_EnterVR( engine_t* engine ) { ALOGE("Failed to create XR session: %d.", initResult); exit(1); } -#ifdef OPENXR_PLATFORM_PICO - pfnXrSetConfigPICO(engine->appState.Session, TRACKING_ORIGIN, "1"); -#endif // Create a space to the first path XrReferenceSpaceCreateInfo spaceCreateInfo = {}; @@ -229,3 +224,11 @@ void VR_LeaveVR( engine_t* engine ) { engine_t* VR_GetEngine( void ) { return &vr_engine; } + +bool VR_GetPlatformFlag(VRPlatformFlag flag) { + return vr_platform[flag]; +} + +void VR_SetPlatformFLag(VRPlatformFlag flag, bool value) { + vr_platform[flag] = value; +} diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index a94e3d3fa9..25efb1b712 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -5,51 +5,20 @@ #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "OpenXR", __VA_ARGS__); #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OpenXR", __VA_ARGS__); #else +#include #define ALOGE(...) printf(__VA_ARGS__) #define ALOGV(...) printf(__VA_ARGS__) #endif -//OpenXR -#define XR_USE_PLATFORM_ANDROID 1 -#define XR_USE_GRAPHICS_API_OPENGL_ES 1 -#include -#include -#include -#include -#include -#include -#include -#include +#include "Common/VR/OpenXRLoader.h" -#ifdef _DEBUG -static const char* GlErrorString(GLenum error) { - switch (error) { - case GL_NO_ERROR: - return "GL_NO_ERROR"; - case GL_INVALID_ENUM: - return "GL_INVALID_ENUM"; - case GL_INVALID_VALUE: - return "GL_INVALID_VALUE"; - case GL_INVALID_OPERATION: - return "GL_INVALID_OPERATION"; - case GL_INVALID_FRAMEBUFFER_OPERATION: - return "GL_INVALID_FRAMEBUFFER_OPERATION"; - case GL_OUT_OF_MEMORY: - return "GL_OUT_OF_MEMORY"; - default: - return "unknown"; - } -} +#define _USE_MATH_DEFINES +#include +#include -static void GLCheckErrors(char* file, int line) { - for (int i = 0; i < 10; i++) { - const GLenum error = glGetError(); - if (error == GL_NO_ERROR) { - break; - } - ALOGE("GL error on line %s:%d %s", file, line, GlErrorString(error)); - } -} +#if defined(_DEBUG) && (defined(XR_USE_GRAPHICS_API_OPENGL) || defined(XR_USE_GRAPHICS_API_OPENGL_ES)) + +void GLCheckErrors(const char* file, int line); #define GL(func) func; GLCheckErrors(__FILE__ , __LINE__); #else @@ -73,11 +42,7 @@ static void OXR_CheckErrors(XrInstance instance, XrResult result, const char* fu #define OXR(func) func; #endif -#ifdef OPENXR_PLATFORM_QUEST -#define OPENXR_HAS_PERFORMANCE_EXTENSION -#endif - -enum { ovrMaxLayerCount = 1 }; +enum { ovrMaxLayerCount = 2 }; enum { ovrMaxNumEyes = 2 }; typedef union { @@ -98,10 +63,15 @@ typedef struct { uint32_t TextureSwapChainIndex; ovrSwapChain ColorSwapChain; ovrSwapChain DepthSwapChain; - XrSwapchainImageOpenGLESKHR* ColorSwapChainImage; - XrSwapchainImageOpenGLESKHR* DepthSwapChainImage; - unsigned int* FrameBuffers; + void* ColorSwapChainImage; + void* DepthSwapChainImage; + unsigned int* GLFrameBuffers; + VkFramebuffer* VKFrameBuffers; + VkImageView* VKColorImages; + VkImageView* VKDepthImages; + bool Acquired; + XrGraphicsBindingVulkanKHR* VKContext; } ovrFramebuffer; typedef struct { @@ -133,27 +103,39 @@ typedef struct { ovrRenderer Renderer; } ovrApp; +#ifdef ANDROID typedef struct { JavaVM* Vm; jobject ActivityObject; JNIEnv* Env; - char AppName[64]; - int AppVersion; } ovrJava; +#endif typedef struct { uint64_t frameIndex; ovrApp appState; - ovrJava java; - float predictedDisplayTime; + XrTime predictedDisplayTime; + XrGraphicsBindingVulkanKHR graphicsBindingVulkan; } engine_t; -void VR_Init( ovrJava java ); +enum VRPlatformFlag { + VR_PLATFORM_CONTROLLER_PICO, + VR_PLATFORM_CONTROLLER_QUEST, + VR_PLATFORM_INSTANCE_EXT, + VR_PLATFORM_PERFORMANCE_EXT, + VR_PLATFORM_RENDERER_VULKAN, + VR_PLATFORM_TRACKING_FLOOR, + VR_PLATFORM_MAX +}; + +void VR_Init( void* system, const char* name, int version ); void VR_Destroy( engine_t* engine ); -void VR_EnterVR( engine_t* engine ); +void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVulkan ); void VR_LeaveVR( engine_t* engine ); engine_t* VR_GetEngine( void ); +bool VR_GetPlatformFlag(VRPlatformFlag flag); +void VR_SetPlatformFLag(VRPlatformFlag flag, bool value); void ovrApp_Clear(ovrApp* app); void ovrApp_Destroy(ovrApp* app); diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 9dab8411e3..792dd5a879 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -1,17 +1,23 @@ #include "VRFramebuffer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#if XR_USE_GRAPHICS_API_OPENGL_ES + #include #include +#endif + +#include +#include +#include +#include +#include +#include + +#if !defined(_WIN32) +#include +#endif + double FromXrTime(const XrTime time) { return (time * 1e-9); } @@ -39,12 +45,46 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->DepthSwapChain.Height = 0; frameBuffer->DepthSwapChainImage = NULL; - frameBuffer->FrameBuffers = NULL; + frameBuffer->GLFrameBuffers = NULL; frameBuffer->Acquired = false; } -bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES +static const char* GlErrorString(GLenum error) { + switch (error) { + case GL_NO_ERROR: + return "GL_NO_ERROR"; + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + default: + return "unknown"; + } +} + +void GLCheckErrors(const char* file, int line) { + for (int i = 0; i < 10; i++) { + const GLenum error = glGetError(); + if (error == GL_NO_ERROR) { + break; + } + ALOGE("GL error on line %s:%d %s", file, line, GlErrorString(error)); + } +} + +#endif + +#if XR_USE_GRAPHICS_API_OPENGL_ES + +static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { frameBuffer->Width = width; frameBuffer->Height = height; @@ -54,12 +94,11 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w } typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei); - auto glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultiviewOVR"); - if (!glFramebufferTextureMultiviewOVR) - { + PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR glFramebufferTextureMultiviewOVR = nullptr; + glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultiviewOVR"); + if (!glFramebufferTextureMultiviewOVR) { ALOGE("Can not get proc address for glFramebufferTextureMultiviewOVR.\n"); } - XrSwapchainCreateInfo swapChainCreateInfo; memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo)); swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO; @@ -80,20 +119,20 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle)); OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL)); - frameBuffer->ColorSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); + frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); // Create the depth swapchain. swapChainCreateInfo.format = GL_DEPTH24_STENCIL8; swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle)); - frameBuffer->DepthSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); + frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); // Populate the swapchain image array. for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - frameBuffer->ColorSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; - frameBuffer->ColorSwapChainImage[i].next = NULL; - frameBuffer->DepthSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; - frameBuffer->DepthSwapChainImage[i].next = NULL; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; + ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL; } OXR(xrEnumerateSwapchainImages( frameBuffer->ColorSwapChain.Handle, @@ -106,14 +145,14 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w &frameBuffer->TextureSwapChainLength, (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); - frameBuffer->FrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint)); + frameBuffer->GLFrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint)); for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - const GLuint colorTexture = frameBuffer->ColorSwapChainImage[i].image; - const GLuint depthTexture = frameBuffer->DepthSwapChainImage[i].image; + const GLuint colorTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].image; + const GLuint depthTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].image; // Create the frame buffer. - GL(glGenFramebuffers(1, &frameBuffer->FrameBuffers[i])); - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[i])); + GL(glGenFramebuffers(1, &frameBuffer->GLFrameBuffers[i])); + GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[i])); if (multiview) { GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexture, 0, 0, 2)); GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0, 2)); @@ -134,29 +173,148 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w return true; } +#endif + +#if XR_USE_GRAPHICS_API_VULKAN + +static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, + bool multiview, void* context) { + + frameBuffer->Width = width; + frameBuffer->Height = height; + frameBuffer->VKContext = (XrGraphicsBindingVulkanKHR*)context; + + XrSwapchainCreateInfo swapChainCreateInfo; + memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo)); + swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO; + swapChainCreateInfo.sampleCount = 1; + swapChainCreateInfo.width = width; + swapChainCreateInfo.height = height; + swapChainCreateInfo.faceCount = 1; + swapChainCreateInfo.mipCount = 1; + swapChainCreateInfo.arraySize = multiview ? 2 : 1; + + frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width; + frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height; + frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width; + frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height; + + // Create the color swapchain. + swapChainCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; + OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle)); + OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL)); + frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR)); + + // Create the depth swapchain. + swapChainCreateInfo.format = VK_FORMAT_D24_UNORM_S8_UINT; + swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle)); + frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR)); + + // Populate the swapchain image array. + for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; + ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL; + ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; + ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL; + } + OXR(xrEnumerateSwapchainImages( + frameBuffer->ColorSwapChain.Handle, + frameBuffer->TextureSwapChainLength, + &frameBuffer->TextureSwapChainLength, + (XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage)); + OXR(xrEnumerateSwapchainImages( + frameBuffer->DepthSwapChain.Handle, + frameBuffer->TextureSwapChainLength, + &frameBuffer->TextureSwapChainLength, + (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); + + frameBuffer->VKColorImages = new VkImageView[frameBuffer->TextureSwapChainLength]; + frameBuffer->VKDepthImages = new VkImageView[frameBuffer->TextureSwapChainLength]; + frameBuffer->VKFrameBuffers = new VkFramebuffer[frameBuffer->TextureSwapChainLength]; + for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { + VkImageViewCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].image; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = swapChainCreateInfo.arraySize; + if (vkCreateImageView(frameBuffer->VKContext->device, &createInfo, nullptr, &frameBuffer->VKColorImages[i]) != VK_SUCCESS) { + ALOGE("failed to create color image view!"); + return false; + } + + createInfo.image = ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].image; + createInfo.format = VK_FORMAT_D24_UNORM_S8_UINT; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (vkCreateImageView(frameBuffer->VKContext->device, &createInfo, nullptr, &frameBuffer->VKDepthImages[i]) != VK_SUCCESS) { + ALOGE("failed to create depth image view!"); + return false; + } + + // Create the frame buffer. + VkImageView attachments[] = { frameBuffer->VKColorImages[i], frameBuffer->VKDepthImages[i] }; + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = VK_NULL_HANDLE; //TODO:This is probably wrong + framebufferInfo.attachmentCount = 2; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = width; + framebufferInfo.height = height; + framebufferInfo.layers = swapChainCreateInfo.arraySize; + if (vkCreateFramebuffer(frameBuffer->VKContext->device, &framebufferInfo, nullptr, &frameBuffer->VKFrameBuffers[i]) != VK_SUCCESS) { + ALOGE("failed to create framebuffer!"); + return false; + } + } + + return true; +} + +#endif + void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { - GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->FrameBuffers)); + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + for (int i = 0; i < (int)frameBuffer->TextureSwapChainLength; i++) { + vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKColorImages[i], nullptr); + vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKDepthImages[i], nullptr); + vkDestroyFramebuffer(frameBuffer->VKContext->device, frameBuffer->VKFrameBuffers[i], nullptr); + } + delete[] frameBuffer->VKColorImages; + delete[] frameBuffer->VKDepthImages; + delete[] frameBuffer->VKFrameBuffers; + } else { +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); + free(frameBuffer->GLFrameBuffers); +#endif + } OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle)); OXR(xrDestroySwapchain(frameBuffer->DepthSwapChain.Handle)); free(frameBuffer->ColorSwapChainImage); free(frameBuffer->DepthSwapChainImage); - free(frameBuffer->FrameBuffers); ovrFramebuffer_Clear(frameBuffer); } -void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex])); -} - -void ovrFramebuffer_SetNone() { - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); -} - -void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer) { - // Discard the depth buffer, so the tiler won't need to write it back out to memory. - const GLenum depthAttachment[1] = {GL_DEPTH_ATTACHMENT}; - glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, depthAttachment); +void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + return (void *)frameBuffer->VKFrameBuffers[frameBuffer->TextureSwapChainIndex]; + } else { +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[frameBuffer->TextureSwapChainIndex])); +#endif + return nullptr; + } } void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { @@ -178,6 +336,22 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { waitInfo.timeout * (1E-9)); } frameBuffer->Acquired = res == XR_SUCCESS; + + ovrFramebuffer_SetCurrent(frameBuffer); + + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + //TODO:implement + } else { +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + GL(glEnable( GL_SCISSOR_TEST )); + GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); + GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); + GL(glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height )); + GL(glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )); + GL(glScissor( 0, 0, 0, 0 )); + GL(glDisable( GL_SCISSOR_TEST )); +#endif + } } void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { @@ -185,6 +359,18 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) { XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL}; OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo)); frameBuffer->Acquired = false; + + // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + //TODO:implement + } else { +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE)); + GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); + GL(glClear(GL_COLOR_BUFFER_BIT)); + GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); +#endif + } } } @@ -202,11 +388,19 @@ void ovrRenderer_Clear(ovrRenderer* renderer) { } } -void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview) { +void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext) { renderer->Multiview = multiview; int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; for (int i = 0; i < instances; i++) { - ovrFramebuffer_Create(session, &renderer->FrameBuffer[i], width, height, multiview); + if (vulkanContext) { + ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); + } else { +#if XR_USE_GRAPHICS_API_OPENGL_ES + ovrFramebuffer_CreateGLES(session, &renderer->FrameBuffer[i], width, height, multiview); +#elif XR_USE_GRAPHICS_API_OPENGL + // TODO +#endif + } } } @@ -217,6 +411,21 @@ void ovrRenderer_Destroy(ovrRenderer* renderer) { } } +void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy) { + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + //TODO:implement + } else { +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + GL(glEnable(GL_SCISSOR_TEST)); + GL(glScissor(x, y, sx, sy)); + GL(glViewport(x, y, sx, sy)); + GL(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); + GL(glClear(GL_COLOR_BUFFER_BIT)); + GL(glDisable(GL_SCISSOR_TEST)); +#endif + } +} + /* ================================================================================ @@ -250,6 +459,7 @@ void ovrApp_Destroy(ovrApp* app) { ovrApp_Clear(app); } + void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { if (state == XR_SESSION_STATE_READY) { assert(app->SessionActive == false); @@ -262,12 +472,10 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) { XrResult result; OXR(result = xrBeginSession(app->Session, &sessionBeginInfo)); - app->SessionActive = (result == XR_SUCCESS); - // Set session state once we have entered VR mode and have a valid session object. -#ifdef OPENXR_HAS_PERFORMANCE_EXTENSION - if (app->SessionActive) { +#ifdef ANDROID + if (app->SessionActive && VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) { XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT; diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index dcedad580f..07a5c19834 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -1,16 +1,15 @@ #pragma once -#include "VR/VRBase.h" +#include "VRBase.h" void ovrApp_Clear(ovrApp* app); void ovrApp_Destroy(ovrApp* app); int ovrApp_HandleXrEvents(ovrApp* app); void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); -void ovrFramebuffer_SetNone(); +void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); -void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview); +void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext); void ovrRenderer_Destroy(ovrRenderer* renderer); +void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy); diff --git a/Common/VR/VRInput.cpp b/Common/VR/VRInput.cpp index 2fc8816f61..dec132ab34 100644 --- a/Common/VR/VRInput.cpp +++ b/Common/VR/VRInput.cpp @@ -1,6 +1,5 @@ #include "VRInput.h" -#include -#include +#include //OpenXR XrPath leftHandPath; @@ -38,6 +37,8 @@ XrActionStateVector2f moveJoystickState[2]; float vibration_channel_duration[2] = {0.0f, 0.0f}; float vibration_channel_intensity[2] = {0.0f, 0.0f}; +#if !defined(_WIN32) +#include unsigned long sys_timeBase = 0; int milliseconds(void) { @@ -47,14 +48,33 @@ int milliseconds(void) { if (!sys_timeBase) { sys_timeBase = tp.tv_sec; - return tp.tv_usec/1000; + return tp.tv_usec / 1000; } - return (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000; + return (tp.tv_sec - sys_timeBase) * 1000 + tp.tv_usec / 1000; +} +#else + +static LARGE_INTEGER frequency; +static double frequencyMult; +static LARGE_INTEGER startTime; + +int milliseconds() { + if (frequency.QuadPart == 0) { + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&startTime); + frequencyMult = 1.0 / static_cast(frequency.QuadPart); + } + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + double elapsed = static_cast(time.QuadPart - startTime.QuadPart); + return (int)(elapsed * frequencyMult * 1000.0); } +#endif + XrTime ToXrTime(const double timeInSeconds) { - return (timeInSeconds * 1e9); + return (XrTime)(timeInSeconds * 1e9); } void INVR_Vibrate( int duration, int chan, float intensity ) { @@ -67,16 +87,15 @@ void INVR_Vibrate( int duration, int chan, float intensity ) { if (vibration_channel_duration[channel] == -1.0f && duration != 0.0f) return; - vibration_channel_duration[channel] = duration; + vibration_channel_duration[channel] = (float)duration; vibration_channel_intensity[channel] = intensity; } } } - void VR_processHaptics() { float lastFrameTime = 0.0f; - float timestamp = (float)(milliseconds( )); + float timestamp = (float)(milliseconds()); float frametime = timestamp - lastFrameTime; lastFrameTime = timestamp; @@ -247,25 +266,27 @@ void IN_VRInit( engine_t *engine ) { handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath); XrPath interactionProfilePath = XR_NULL_PATH; -#ifdef OPENXR_PLATFORM_QUEST - OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePath)); -#elif OPENXR_PLATFORM_PICO - OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/pico/neo3_controller", &interactionProfilePath)); -#endif + if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_QUEST)) { + OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePath)); + } else if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_PICO)) { + OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/pico/neo3_controller", &interactionProfilePath)); + } + // Map bindings XrActionSuggestedBinding bindings[32]; // large enough for all profiles int currBinding = 0; -#ifdef OPENXR_PLATFORM_QUEST - bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); - bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); -#elif OPENXR_PLATFORM_PICO - bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger/click"); - bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger/click"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/back/click"); - bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/right/input/back/click"); -#endif + + if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_QUEST)) { + bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger"); + bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click"); + } else if (VR_GetPlatformFlag(VR_PLATFORM_CONTROLLER_PICO)) { + bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger/click"); + bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger/click"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/back/click"); + bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/right/input/back/click"); + } bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click"); bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click"); @@ -438,6 +459,6 @@ XrPosef IN_VRGetPose( int controllerIndex ) { XrSpaceLocation loc = {}; loc.type = XR_TYPE_SPACE_LOCATION; XrSpace aimSpace[] = { leftControllerAimSpace, rightControllerAimSpace }; - xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc); + xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, (XrTime)(engine->predictedDisplayTime), &loc); return loc.pose; } diff --git a/Common/VR/VRMath.cpp b/Common/VR/VRMath.cpp index 204e591fad..d65f13a1a7 100644 --- a/Common/VR/VRMath.cpp +++ b/Common/VR/VRMath.cpp @@ -1,3 +1,8 @@ +#define _USE_MATH_DEFINES + +#include +#include + #include "VRMath.h" float ToDegrees(float rad) { @@ -8,223 +13,18 @@ float ToRadians(float deg) { return (float)(deg * M_PI / 180.0f); } -/* -================================================================================ +bool IsMatrixIdentity(float* matrix) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float value = matrix[i * 4 + j]; -ovrMatrix4f - -================================================================================ -*/ - -float ovrMatrix4f_Minor(const ovrMatrix4f* m, int r0, int r1, int r2, int c0, int c1, int c2) { - return m->M[r0][c0] * (m->M[r1][c1] * m->M[r2][c2] - m->M[r2][c1] * m->M[r1][c2]) - - m->M[r0][c1] * (m->M[r1][c0] * m->M[r2][c2] - m->M[r2][c0] * m->M[r1][c2]) + - m->M[r0][c2] * (m->M[r1][c0] * m->M[r2][c1] - m->M[r2][c0] * m->M[r1][c1]); -} - -ovrMatrix4f ovrMatrix4f_CreateFromQuaternion(const XrQuaternionf* q) { - const float ww = q->w * q->w; - const float xx = q->x * q->x; - const float yy = q->y * q->y; - const float zz = q->z * q->z; - - ovrMatrix4f out; - out.M[0][0] = ww + xx - yy - zz; - out.M[0][1] = 2 * (q->x * q->y - q->w * q->z); - out.M[0][2] = 2 * (q->x * q->z + q->w * q->y); - out.M[0][3] = 0; - - out.M[1][0] = 2 * (q->x * q->y + q->w * q->z); - out.M[1][1] = ww - xx + yy - zz; - out.M[1][2] = 2 * (q->y * q->z - q->w * q->x); - out.M[1][3] = 0; - - out.M[2][0] = 2 * (q->x * q->z - q->w * q->y); - out.M[2][1] = 2 * (q->y * q->z + q->w * q->x); - out.M[2][2] = ww - xx - yy + zz; - out.M[2][3] = 0; - - out.M[3][0] = 0; - out.M[3][1] = 0; - out.M[3][2] = 0; - out.M[3][3] = 1; - return out; -} - -ovrMatrix4f ovrMatrix4f_CreateProjectionFov( - const float angleLeft, - const float angleRight, - const float angleUp, - const float angleDown, - const float nearZ, - const float farZ) { - - const float tanAngleLeft = tanf(angleLeft); - const float tanAngleRight = tanf(angleRight); - - const float tanAngleDown = tanf(angleDown); - const float tanAngleUp = tanf(angleUp); - - const float tanAngleWidth = tanAngleRight - tanAngleLeft; - - // Set to tanAngleDown - tanAngleUp for a clip space with positive Y - // down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with - // positive Y up (OpenGL / D3D / Metal). - const float tanAngleHeight = tanAngleUp - tanAngleDown; - - // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). - // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). - const float offsetZ = nearZ; - - ovrMatrix4f result; - if (farZ <= nearZ) { - // place the far plane at infinity - result.M[0][0] = 2 / tanAngleWidth; - result.M[0][1] = 0; - result.M[0][2] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; - result.M[0][3] = 0; - - result.M[1][0] = 0; - result.M[1][1] = 2 / tanAngleHeight; - result.M[1][2] = (tanAngleUp + tanAngleDown) / tanAngleHeight; - result.M[1][3] = 0; - - result.M[2][0] = 0; - result.M[2][1] = 0; - result.M[2][2] = -1; - result.M[2][3] = -(nearZ + offsetZ); - - result.M[3][0] = 0; - result.M[3][1] = 0; - result.M[3][2] = -1; - result.M[3][3] = 0; - } else { - // normal projection - result.M[0][0] = 2 / tanAngleWidth; - result.M[0][1] = 0; - result.M[0][2] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; - result.M[0][3] = 0; - - result.M[1][0] = 0; - result.M[1][1] = 2 / tanAngleHeight; - result.M[1][2] = (tanAngleUp + tanAngleDown) / tanAngleHeight; - result.M[1][3] = 0; - - result.M[2][0] = 0; - result.M[2][1] = 0; - result.M[2][2] = -(farZ + offsetZ) / (farZ - nearZ); - result.M[2][3] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ); - - result.M[3][0] = 0; - result.M[3][1] = 0; - result.M[3][2] = -1; - result.M[3][3] = 0; + // Other number than zero on non-diagonale + if ((i != j) && (fabs(value) > EPSILON)) return false; + // Other number than one on diagonale + if ((i == j) && (fabs(value - 1.0f) > EPSILON)) return false; + } } - return result; -} - -ovrMatrix4f ovrMatrix4f_CreateRotation(const float radiansX, const float radiansY, const float radiansZ) { - const float sinX = sinf(radiansX); - const float cosX = cosf(radiansX); - const ovrMatrix4f rotationX = { - {{1, 0, 0, 0}, {0, cosX, -sinX, 0}, {0, sinX, cosX, 0}, {0, 0, 0, 1}}}; - const float sinY = sinf(radiansY); - const float cosY = cosf(radiansY); - const ovrMatrix4f rotationY = { - {{cosY, 0, sinY, 0}, {0, 1, 0, 0}, {-sinY, 0, cosY, 0}, {0, 0, 0, 1}}}; - const float sinZ = sinf(radiansZ); - const float cosZ = cosf(radiansZ); - const ovrMatrix4f rotationZ = { - {{cosZ, -sinZ, 0, 0}, {sinZ, cosZ, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}}; - const ovrMatrix4f rotationXY = ovrMatrix4f_Multiply(&rotationY, &rotationX); - return ovrMatrix4f_Multiply(&rotationZ, &rotationXY); -} - -ovrMatrix4f ovrMatrix4f_Inverse(const ovrMatrix4f* m) { - const float rcpDet = 1.0f / - (m->M[0][0] * ovrMatrix4f_Minor(m, 1, 2, 3, 1, 2, 3) - - m->M[0][1] * ovrMatrix4f_Minor(m, 1, 2, 3, 0, 2, 3) + - m->M[0][2] * ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 3) - - m->M[0][3] * ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 2)); - ovrMatrix4f out; - out.M[0][0] = ovrMatrix4f_Minor(m, 1, 2, 3, 1, 2, 3) * rcpDet; - out.M[0][1] = -ovrMatrix4f_Minor(m, 0, 2, 3, 1, 2, 3) * rcpDet; - out.M[0][2] = ovrMatrix4f_Minor(m, 0, 1, 3, 1, 2, 3) * rcpDet; - out.M[0][3] = -ovrMatrix4f_Minor(m, 0, 1, 2, 1, 2, 3) * rcpDet; - out.M[1][0] = -ovrMatrix4f_Minor(m, 1, 2, 3, 0, 2, 3) * rcpDet; - out.M[1][1] = ovrMatrix4f_Minor(m, 0, 2, 3, 0, 2, 3) * rcpDet; - out.M[1][2] = -ovrMatrix4f_Minor(m, 0, 1, 3, 0, 2, 3) * rcpDet; - out.M[1][3] = ovrMatrix4f_Minor(m, 0, 1, 2, 0, 2, 3) * rcpDet; - out.M[2][0] = ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 3) * rcpDet; - out.M[2][1] = -ovrMatrix4f_Minor(m, 0, 2, 3, 0, 1, 3) * rcpDet; - out.M[2][2] = ovrMatrix4f_Minor(m, 0, 1, 3, 0, 1, 3) * rcpDet; - out.M[2][3] = -ovrMatrix4f_Minor(m, 0, 1, 2, 0, 1, 3) * rcpDet; - out.M[3][0] = -ovrMatrix4f_Minor(m, 1, 2, 3, 0, 1, 2) * rcpDet; - out.M[3][1] = ovrMatrix4f_Minor(m, 0, 2, 3, 0, 1, 2) * rcpDet; - out.M[3][2] = -ovrMatrix4f_Minor(m, 0, 1, 3, 0, 1, 2) * rcpDet; - out.M[3][3] = ovrMatrix4f_Minor(m, 0, 1, 2, 0, 1, 2) * rcpDet; - return out; -} - -/// Use left-multiplication to accumulate transformations. -ovrMatrix4f ovrMatrix4f_Multiply(const ovrMatrix4f* a, const ovrMatrix4f* b) { - ovrMatrix4f out; - out.M[0][0] = a->M[0][0] * b->M[0][0] + a->M[0][1] * b->M[1][0] + a->M[0][2] * b->M[2][0] + - a->M[0][3] * b->M[3][0]; - out.M[1][0] = a->M[1][0] * b->M[0][0] + a->M[1][1] * b->M[1][0] + a->M[1][2] * b->M[2][0] + - a->M[1][3] * b->M[3][0]; - out.M[2][0] = a->M[2][0] * b->M[0][0] + a->M[2][1] * b->M[1][0] + a->M[2][2] * b->M[2][0] + - a->M[2][3] * b->M[3][0]; - out.M[3][0] = a->M[3][0] * b->M[0][0] + a->M[3][1] * b->M[1][0] + a->M[3][2] * b->M[2][0] + - a->M[3][3] * b->M[3][0]; - - out.M[0][1] = a->M[0][0] * b->M[0][1] + a->M[0][1] * b->M[1][1] + a->M[0][2] * b->M[2][1] + - a->M[0][3] * b->M[3][1]; - out.M[1][1] = a->M[1][0] * b->M[0][1] + a->M[1][1] * b->M[1][1] + a->M[1][2] * b->M[2][1] + - a->M[1][3] * b->M[3][1]; - out.M[2][1] = a->M[2][0] * b->M[0][1] + a->M[2][1] * b->M[1][1] + a->M[2][2] * b->M[2][1] + - a->M[2][3] * b->M[3][1]; - out.M[3][1] = a->M[3][0] * b->M[0][1] + a->M[3][1] * b->M[1][1] + a->M[3][2] * b->M[2][1] + - a->M[3][3] * b->M[3][1]; - - out.M[0][2] = a->M[0][0] * b->M[0][2] + a->M[0][1] * b->M[1][2] + a->M[0][2] * b->M[2][2] + - a->M[0][3] * b->M[3][2]; - out.M[1][2] = a->M[1][0] * b->M[0][2] + a->M[1][1] * b->M[1][2] + a->M[1][2] * b->M[2][2] + - a->M[1][3] * b->M[3][2]; - out.M[2][2] = a->M[2][0] * b->M[0][2] + a->M[2][1] * b->M[1][2] + a->M[2][2] * b->M[2][2] + - a->M[2][3] * b->M[3][2]; - out.M[3][2] = a->M[3][0] * b->M[0][2] + a->M[3][1] * b->M[1][2] + a->M[3][2] * b->M[2][2] + - a->M[3][3] * b->M[3][2]; - - out.M[0][3] = a->M[0][0] * b->M[0][3] + a->M[0][1] * b->M[1][3] + a->M[0][2] * b->M[2][3] + - a->M[0][3] * b->M[3][3]; - out.M[1][3] = a->M[1][0] * b->M[0][3] + a->M[1][1] * b->M[1][3] + a->M[1][2] * b->M[2][3] + - a->M[1][3] * b->M[3][3]; - out.M[2][3] = a->M[2][0] * b->M[0][3] + a->M[2][1] * b->M[1][3] + a->M[2][2] * b->M[2][3] + - a->M[2][3] * b->M[3][3]; - out.M[3][3] = a->M[3][0] * b->M[0][3] + a->M[3][1] * b->M[1][3] + a->M[3][2] * b->M[2][3] + - a->M[3][3] * b->M[3][3]; - return out; -} - -XrVector3f ovrMatrix4f_ToEulerAngles(const ovrMatrix4f* m) { - XrVector4f v1 = {0, 0, -1, 0}; - XrVector4f v2 = {1, 0, 0, 0}; - XrVector4f v3 = {0, 1, 0, 0}; - - XrVector4f forwardInVRSpace = XrVector4f_MultiplyMatrix4f(m, &v1); - XrVector4f rightInVRSpace = XrVector4f_MultiplyMatrix4f(m, &v2); - XrVector4f upInVRSpace = XrVector4f_MultiplyMatrix4f(m, &v3); - - XrVector3f forward = {-forwardInVRSpace.z, -forwardInVRSpace.x, forwardInVRSpace.y}; - XrVector3f right = {-rightInVRSpace.z, -rightInVRSpace.x, rightInVRSpace.y}; - XrVector3f up = {-upInVRSpace.z, -upInVRSpace.x, upInVRSpace.y}; - - XrVector3f forwardNormal = XrVector3f_Normalized(forward); - XrVector3f rightNormal = XrVector3f_Normalized(right); - XrVector3f upNormal = XrVector3f_Normalized(up); - - return XrVector3f_GetAnglesFromVectors(forwardNormal, rightNormal, upNormal); + return true; } /* @@ -236,15 +36,15 @@ XrPosef */ XrPosef XrPosef_Identity() { - XrPosef r; - r.orientation.x = 0; - r.orientation.y = 0; - r.orientation.z = 0; - r.orientation.w = 1; - r.position.x = 0; - r.position.y = 0; - r.position.z = 0; - return r; + XrPosef r; + r.orientation.x = 0; + r.orientation.y = 0; + r.orientation.z = 0; + r.orientation.w = 1; + r.position.x = 0; + r.position.y = 0; + r.position.z = 0; + return r; } XrPosef XrPosef_Inverse(const XrPosef a) { @@ -254,18 +54,6 @@ XrPosef XrPosef_Inverse(const XrPosef a) { return b; } -XrPosef XrPosef_Multiply(const XrPosef a, const XrPosef b) { - XrPosef c; - c.orientation = XrQuaternionf_Multiply(a.orientation, b.orientation); - c.position = XrPosef_Transform(a, b.position); - return c; -} - -XrVector3f XrPosef_Transform(const XrPosef a, const XrVector3f v) { - XrVector3f r0 = XrQuaternionf_Rotate(a.orientation, v); - return XrVector3f_Add(r0, a.position); -} - /* ================================================================================ @@ -325,8 +113,56 @@ XrVector3f XrQuaternionf_Rotate(const XrQuaternionf a, const XrVector3f v) { } XrVector3f XrQuaternionf_ToEulerAngles(const XrQuaternionf q) { - ovrMatrix4f m = ovrMatrix4f_CreateFromQuaternion( &q ); - return ovrMatrix4f_ToEulerAngles(&m); + float M[16]; + XrQuaternionf_ToMatrix4f( &q, M); + + XrVector4f v1 = {0, 0, -1, 0}; + XrVector4f v2 = {1, 0, 0, 0}; + XrVector4f v3 = {0, 1, 0, 0}; + + XrVector4f forwardInVRSpace = XrVector4f_MultiplyMatrix4f(M, &v1); + XrVector4f rightInVRSpace = XrVector4f_MultiplyMatrix4f(M, &v2); + XrVector4f upInVRSpace = XrVector4f_MultiplyMatrix4f(M, &v3); + + XrVector3f forward = {-forwardInVRSpace.z, -forwardInVRSpace.x, forwardInVRSpace.y}; + XrVector3f right = {-rightInVRSpace.z, -rightInVRSpace.x, rightInVRSpace.y}; + XrVector3f up = {-upInVRSpace.z, -upInVRSpace.x, upInVRSpace.y}; + + XrVector3f forwardNormal = XrVector3f_Normalized(forward); + XrVector3f rightNormal = XrVector3f_Normalized(right); + XrVector3f upNormal = XrVector3f_Normalized(up); + + return XrVector3f_GetAnglesFromVectors(forwardNormal, rightNormal, upNormal); +} + +void XrQuaternionf_ToMatrix4f(const XrQuaternionf* q, float* matrix) { + const float ww = q->w * q->w; + const float xx = q->x * q->x; + const float yy = q->y * q->y; + const float zz = q->z * q->z; + + float M[4][4]; + M[0][0] = ww + xx - yy - zz; + M[0][1] = 2 * (q->x * q->y - q->w * q->z); + M[0][2] = 2 * (q->x * q->z + q->w * q->y); + M[0][3] = 0; + + M[1][0] = 2 * (q->x * q->y + q->w * q->z); + M[1][1] = ww - xx + yy - zz; + M[1][2] = 2 * (q->y * q->z - q->w * q->x); + M[1][3] = 0; + + M[2][0] = 2 * (q->x * q->z - q->w * q->y); + M[2][1] = 2 * (q->y * q->z + q->w * q->x); + M[2][2] = ww - xx - yy + zz; + M[2][3] = 0; + + M[3][0] = 0; + M[3][1] = 0; + M[3][2] = 0; + M[3][3] = 1; + + memcpy(matrix, &M, sizeof(float) * 16); } /* @@ -337,22 +173,10 @@ XrVector3f, XrVector4f ================================================================================ */ -float XrVector3f_Length(const XrVector3f v) { - return sqrtf(XrVector3f_LengthSquared(v)); -} - float XrVector3f_LengthSquared(const XrVector3f v) { return v.x * v.x + v.y * v.y + v.z * v.z;; } -XrVector3f XrVector3f_Add(const XrVector3f u, const XrVector3f v) { - XrVector3f w; - w.x = u.x + v.x; - w.y = u.y + v.y; - w.z = u.z + v.z; - return w; -} - XrVector3f XrVector3f_GetAnglesFromVectors(const XrVector3f forward, const XrVector3f right, const XrVector3f up) { float sr, sp, sy, cr, cp, cy; @@ -393,7 +217,7 @@ XrVector3f XrVector3f_GetAnglesFromVectors(const XrVector3f forward, const XrVec } XrVector3f XrVector3f_Normalized(const XrVector3f v) { - float rcpLen = 1.0f / XrVector3f_Length(v); + float rcpLen = 1.0f / sqrtf(XrVector3f_LengthSquared(v)); return XrVector3f_ScalarMultiply(v, rcpLen); } @@ -405,11 +229,14 @@ XrVector3f XrVector3f_ScalarMultiply(const XrVector3f v, float scale) { return u; } -XrVector4f XrVector4f_MultiplyMatrix4f(const ovrMatrix4f* a, const XrVector4f* v) { +XrVector4f XrVector4f_MultiplyMatrix4f(const float* m, const XrVector4f* v) { + float M[4][4]; + memcpy(&M, m, sizeof(float) * 16); + XrVector4f out; - out.x = a->M[0][0] * v->x + a->M[0][1] * v->y + a->M[0][2] * v->z + a->M[0][3] * v->w; - out.y = a->M[1][0] * v->x + a->M[1][1] * v->y + a->M[1][2] * v->z + a->M[1][3] * v->w; - out.z = a->M[2][0] * v->x + a->M[2][1] * v->y + a->M[2][2] * v->z + a->M[2][3] * v->w; - out.w = a->M[3][0] * v->x + a->M[3][1] * v->y + a->M[3][2] * v->z + a->M[3][3] * v->w; + out.x = M[0][0] * v->x + M[0][1] * v->y + M[0][2] * v->z + M[0][3] * v->w; + out.y = M[1][0] * v->x + M[1][1] * v->y + M[1][2] * v->z + M[1][3] * v->w; + out.z = M[2][0] * v->x + M[2][1] * v->y + M[2][2] * v->z + M[2][3] * v->w; + out.w = M[3][0] * v->x + M[3][1] * v->y + M[3][2] * v->z + M[3][3] * v->w; return out; } diff --git a/Common/VR/VRMath.h b/Common/VR/VRMath.h index eb801ac73f..4f6e0610c9 100644 --- a/Common/VR/VRMath.h +++ b/Common/VR/VRMath.h @@ -7,27 +7,13 @@ #define EPSILON 0.001f #endif -typedef struct { - float M[4][4]; -} ovrMatrix4f; - float ToDegrees(float rad); float ToRadians(float deg); - -// ovrMatrix4f -float ovrMatrix4f_Minor(const ovrMatrix4f* m, int r0, int r1, int r2, int c0, int c1, int c2); -ovrMatrix4f ovrMatrix4f_CreateFromQuaternion(const XrQuaternionf* q); -ovrMatrix4f ovrMatrix4f_CreateProjectionFov(const float angleLeft, const float angleRight, const float angleUp, const float angleDown, const float nearZ, const float farZ); -ovrMatrix4f ovrMatrix4f_CreateRotation(const float radiansX, const float radiansY, const float radiansZ); -ovrMatrix4f ovrMatrix4f_Inverse(const ovrMatrix4f* m); -ovrMatrix4f ovrMatrix4f_Multiply(const ovrMatrix4f* a, const ovrMatrix4f* b); -XrVector3f ovrMatrix4f_ToEulerAngles(const ovrMatrix4f* m); +bool IsMatrixIdentity(float* matrix); // XrPosef XrPosef XrPosef_Identity(); XrPosef XrPosef_Inverse(const XrPosef a); -XrPosef XrPosef_Multiply(const XrPosef a, const XrPosef b); -XrVector3f XrPosef_Transform(const XrPosef a, const XrVector3f v); // XrQuaternionf XrQuaternionf XrQuaternionf_CreateFromVectorAngle(const XrVector3f axis, const float angle); @@ -35,12 +21,11 @@ XrQuaternionf XrQuaternionf_Inverse(const XrQuaternionf q); XrQuaternionf XrQuaternionf_Multiply(const XrQuaternionf a, const XrQuaternionf b); XrVector3f XrQuaternionf_Rotate(const XrQuaternionf a, const XrVector3f v); XrVector3f XrQuaternionf_ToEulerAngles(const XrQuaternionf q); +void XrQuaternionf_ToMatrix4f(const XrQuaternionf* q, float* m); // XrVector3f, XrVector4f -float XrVector3f_Length(const XrVector3f v); float XrVector3f_LengthSquared(const XrVector3f v); -XrVector3f XrVector3f_Add(const XrVector3f u, const XrVector3f v); XrVector3f XrVector3f_GetAnglesFromVectors(const XrVector3f forward, const XrVector3f right, const XrVector3f up); XrVector3f XrVector3f_Normalized(const XrVector3f v); XrVector3f XrVector3f_ScalarMultiply(const XrVector3f v, float scale); -XrVector4f XrVector4f_MultiplyMatrix4f(const ovrMatrix4f* a, const XrVector4f* v); +XrVector4f XrVector4f_MultiplyMatrix4f(const float* m, const XrVector4f* v); diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 22668fb3f3..5de7cb4055 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -1,25 +1,24 @@ +#define _USE_MATH_DEFINES +#include + #include "VRBase.h" #include "VRInput.h" #include "VRRenderer.h" +#include "OpenXRLoader.h" -#include -#include -#include - -#include -#include +#include +#include XrFovf fov; XrView* projections; XrPosef invViewTransform[2]; XrFrameState frameState = {}; -GLboolean initialized = GL_FALSE; -GLboolean stageSupported = GL_FALSE; +bool initialized = false; +bool stageSupported = false; int vrConfig[VR_CONFIG_MAX] = {}; -ovrMatrix4f vrMatrix[VR_MATRIX_COUNT]; +float vrConfigFloat[VR_CONFIG_FLOAT_MAX] = {}; XrVector3f hmdorientation; -XrVector3f hmdposition; void VR_UpdateStageBounds(ovrApp* pappState) { XrExtent2Df stageBounds = {}; @@ -134,12 +133,12 @@ void VR_Recenter(engine_t* engine) { OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc)); hmdorientation = XrQuaternionf_ToEulerAngles(loc.pose.orientation); - vrConfig[VR_CONFIG_RECENTER_YAW] += (int)hmdorientation.y; - float recenterYaw = ToRadians((float)vrConfig[VR_CONFIG_RECENTER_YAW]); + VR_SetConfigFloat(VR_CONFIG_RECENTER_YAW, VR_GetConfigFloat(VR_CONFIG_RECENTER_YAW) + hmdorientation.y); + float recenterYaw = ToRadians(VR_GetConfigFloat(VR_CONFIG_RECENTER_YAW)); spaceCreateInfo.poseInReferenceSpace.orientation.x = 0; - spaceCreateInfo.poseInReferenceSpace.orientation.y = sin(recenterYaw / 2); + spaceCreateInfo.poseInReferenceSpace.orientation.y = sinf(recenterYaw / 2); spaceCreateInfo.poseInReferenceSpace.orientation.z = 0; - spaceCreateInfo.poseInReferenceSpace.orientation.w = cos(recenterYaw / 2); + spaceCreateInfo.poseInReferenceSpace.orientation.w = cosf(recenterYaw / 2); } // Delete previous space instances @@ -153,9 +152,9 @@ void VR_Recenter(engine_t* engine) { // Create a default stage space to use if SPACE_TYPE_STAGE is not // supported, or calls to xrGetReferenceSpaceBoundsRect fail. spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; -#ifdef OPENXR_FLOOR_STAGE - spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; -#endif + if (VR_GetPlatformFlag(VR_PLATFORM_TRACKING_FLOOR)) { + spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; + } OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace)); ALOGV("Created fake stage space from local space with offset"); engine->appState.CurrentSpace = engine->appState.FakeStageSpace; @@ -165,14 +164,14 @@ void VR_Recenter(engine_t* engine) { spaceCreateInfo.poseInReferenceSpace.position.y = 0.0; OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace)); ALOGV("Created stage space"); -#ifdef OPENXR_FLOOR_STAGE - engine->appState.CurrentSpace = engine->appState.StageSpace; -#endif + if (VR_GetPlatformFlag(VR_PLATFORM_TRACKING_FLOOR)) { + engine->appState.CurrentSpace = engine->appState.StageSpace; + } } // Update menu orientation - vrConfig[VR_CONFIG_MENU_PITCH] = (int)hmdorientation.x; - vrConfig[VR_CONFIG_MENU_YAW] = 0; + VR_SetConfigFloat(VR_CONFIG_MENU_PITCH, hmdorientation.x); + VR_SetConfigFloat(VR_CONFIG_MENU_YAW, 0.0f); } void VR_InitRenderer( engine_t* engine, bool multiview ) { @@ -182,8 +181,8 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { int eyeW, eyeH; VR_GetResolution(engine, &eyeW, &eyeH); - vrConfig[VR_CONFIG_VIEWPORT_WIDTH] = eyeW; - vrConfig[VR_CONFIG_VIEWPORT_HEIGHT] = eyeH; + VR_SetConfig(VR_CONFIG_VIEWPORT_WIDTH, eyeW); + VR_SetConfig(VR_CONFIG_VIEWPORT_HEIGHT, eyeH); // Get the viewport configuration info for the chosen viewport configuration type. engine->appState.ViewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES; @@ -196,7 +195,7 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { for (uint32_t i = 0; i < numOutputSpaces; i++) { if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) { - stageSupported = GL_TRUE; + stageSupported = true; break; } } @@ -209,46 +208,35 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView))); - ovrRenderer_Create( - engine->appState.Session, - &engine->appState.Renderer, + void* vulkanContext = nullptr; + if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { + vulkanContext = &engine->graphicsBindingVulkan; + } + ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer, engine->appState.ViewConfigurationView[0].recommendedImageRectWidth, engine->appState.ViewConfigurationView[0].recommendedImageRectHeight, - multiview); - initialized = GL_TRUE; + multiview, vulkanContext); + initialized = true; } void VR_DestroyRenderer( engine_t* engine ) { ovrRenderer_Destroy(&engine->appState.Renderer); free(projections); - initialized = GL_FALSE; -} - -void VR_ClearFrameBuffer( int width, int height) { - glEnable( GL_SCISSOR_TEST ); - glViewport( 0, 0, width, height ); - - glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - - glScissor( 0, 0, width, height ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - glScissor( 0, 0, 0, 0 ); - glDisable( GL_SCISSOR_TEST ); + initialized = false; } bool VR_InitFrame( engine_t* engine ) { - GLboolean stageBoundsDirty = GL_TRUE; + bool stageBoundsDirty = true; if (ovrApp_HandleXrEvents(&engine->appState)) { VR_Recenter(engine); } - if (engine->appState.SessionActive == GL_FALSE) { + if (engine->appState.SessionActive == false) { return false; } if (stageBoundsDirty) { VR_UpdateStageBounds(&engine->appState); - stageBoundsDirty = GL_FALSE; + stageBoundsDirty = false; } // NOTE: OpenXR does not use the concept of frame indices. Instead, @@ -306,103 +294,34 @@ bool VR_InitFrame( engine_t* engine ) { // Update HMD and controllers hmdorientation = XrQuaternionf_ToEulerAngles(invViewTransform[0].orientation); - hmdposition = invViewTransform[0].position; IN_VRInputFrame(engine); engine->appState.LayerCount = 0; memset(engine->appState.Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount); - - // Update matrices - for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { - if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { - float near = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; - vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, near, 0.0f ); - } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { - XrPosef invView = invViewTransform[0]; - - // get axis mirroring configuration - float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1 : 1; - float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1 : 1; - float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1 : 1; - - // ensure there is maximally one axis to mirror rotation - if (mx + my + mz < 0) { - mx *= -1.0f; - my *= -1.0f; - mz *= -1.0f; - } else { - invView = XrPosef_Inverse(invView); - } - - // create updated quaternion - if (mx + my + mz < 3 - EPSILON) { - XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); - XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); - XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); - XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); - invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); - } - - vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); - float scale = (float)VR_GetConfig(VR_CONFIG_6DOF_SCALE) * 0.000001f; - if (vrConfig[VR_CONFIG_6DOF_ENABLED]) { - vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; - vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; - vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; - } - if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { - float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); - float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); - float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); - float ipd = sqrt(dx * dx + dy * dy + dz * dz); - XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; - separation = XrQuaternionf_Rotate(invView.orientation, separation); - separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - vrMatrix[matrix].M[0][3] -= separation.x; - vrMatrix[matrix].M[1][3] -= separation.y; - vrMatrix[matrix].M[2][3] -= separation.z; - } - } else { - assert(false); - } - } return true; } void VR_BeginFrame( engine_t* engine, int fboIndex ) { vrConfig[VR_CONFIG_CURRENT_FBO] = fboIndex; - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; - ovrFramebuffer_Acquire(frameBuffer); - ovrFramebuffer_SetCurrent(frameBuffer); - VR_ClearFrameBuffer(frameBuffer->ColorSwapChain.Width, frameBuffer->ColorSwapChain.Height); + ovrFramebuffer_Acquire(&engine->appState.Renderer.FrameBuffer[fboIndex]); } void VR_EndFrame( engine_t* engine ) { - int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; - - // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully VR_BindFramebuffer(engine); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Show mouse cursor - int size = vrConfig[VR_CONFIG_MOUSE_SIZE]; - if ((vrConfig[VR_CONFIG_MODE] == VR_MODE_FLAT_SCREEN) && (size > 0)) { - glEnable(GL_SCISSOR_TEST); - glScissor(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size); - glViewport(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size); - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); + int vrMode = vrConfig[VR_CONFIG_MODE]; + bool screenMode = (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); + if (screenMode && (vrConfig[VR_CONFIG_MOUSE_SIZE] > 0)) { + int x = vrConfig[VR_CONFIG_MOUSE_X]; + int y = vrConfig[VR_CONFIG_MOUSE_Y]; + int sx = vrConfig[VR_CONFIG_MOUSE_SIZE]; + int sy = (int)((float)sx * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT)); + ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, sx, sy); } - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; - //ovrFramebuffer_Resolve(frameBuffer); - ovrFramebuffer_Release(frameBuffer); - ovrFramebuffer_SetNone(); + ovrFramebuffer_Release(&engine->appState.Renderer.FrameBuffer[fboIndex]); } void VR_FinishFrame( engine_t* engine ) { @@ -410,7 +329,7 @@ void VR_FinishFrame( engine_t* engine ) { int vrMode = vrConfig[VR_CONFIG_MODE]; XrCompositionLayerProjectionView projection_layer_elements[2] = {}; if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) { - vrConfig[VR_CONFIG_MENU_YAW] = (int)hmdorientation.y; + VR_SetConfigFloat(VR_CONFIG_MENU_YAW, hmdorientation.y); for (int eye = 0; eye < ovrMaxNumEyes; eye++) { int imageLayer = engine->appState.Renderer.Multiview ? eye : 0; @@ -446,40 +365,55 @@ void VR_FinishFrame( engine_t* engine ) { projection_layer.views = projection_layer_elements; engine->appState.Layers[engine->appState.LayerCount++].Projection = projection_layer; - } else if (vrMode == VR_MODE_FLAT_SCREEN) { + } else if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { - // Build the cylinder layer - int width = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Width; - int height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height; + // Flat screen pose + float distance = VR_GetConfigFloat(VR_CONFIG_CANVAS_DISTANCE); + float menuPitch = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_PITCH)); + float menuYaw = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_YAW)); + XrVector3f pos = { + invViewTransform[0].position.x - sinf(menuYaw) * distance, + invViewTransform[0].position.y, + invViewTransform[0].position.z - cosf(menuYaw) * distance + }; + XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -menuPitch); + XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, menuYaw); + + // Setup the cylinder layer XrCompositionLayerCylinderKHR cylinder_layer = {}; cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR; cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; cylinder_layer.space = engine->appState.CurrentSpace; - cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage)); - cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Handle; cylinder_layer.subImage.imageRect.offset.x = 0; cylinder_layer.subImage.imageRect.offset.y = 0; - cylinder_layer.subImage.imageRect.extent.width = width; - cylinder_layer.subImage.imageRect.extent.height = height; + cylinder_layer.subImage.imageRect.extent.width = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Width; + cylinder_layer.subImage.imageRect.extent.height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height; + cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Handle; cylinder_layer.subImage.imageArrayIndex = 0; - float distance = (float)vrConfig[VR_CONFIG_CANVAS_DISTANCE]; - float menuPitch = ToRadians((float)vrConfig[VR_CONFIG_MENU_PITCH]); - float menuYaw = ToRadians((float)vrConfig[VR_CONFIG_MENU_YAW]); - XrVector3f pos = { - invViewTransform[0].position.x - sin(menuYaw) * distance, - invViewTransform[0].position.y, - invViewTransform[0].position.z - cos(menuYaw) * distance - }; - XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -menuPitch); - XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, menuYaw); cylinder_layer.pose.orientation = XrQuaternionf_Multiply(pitch, yaw); cylinder_layer.pose.position = pos; cylinder_layer.radius = 12.0f; - cylinder_layer.centralAngle = M_PI * 0.5f; - cylinder_layer.aspectRatio = 1; + cylinder_layer.centralAngle = (float)(M_PI * 0.5); + cylinder_layer.aspectRatio = VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); - engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + // Build the cylinder layer + if (vrMode == VR_MODE_MONO_SCREEN) { + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + } else if (engine->appState.Renderer.Multiview) { + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT; + cylinder_layer.subImage.imageArrayIndex = 1; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + } else { + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT; + cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[1].ColorSwapChain.Handle; + engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; + } } else { assert(false); } @@ -514,15 +448,20 @@ void VR_SetConfig( VRConfig config, int value) { vrConfig[config] = value; } -void VR_BindFramebuffer(engine_t *engine) { - if (!initialized) return; - int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; - unsigned int swapchainIndex = frameBuffer->TextureSwapChainIndex; - unsigned int glFramebuffer = frameBuffer->FrameBuffers[swapchainIndex]; - GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, glFramebuffer)); +float VR_GetConfigFloat(VRConfigFloat config) { + return vrConfigFloat[config]; } -ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { - return vrMatrix[matrix]; +void VR_SetConfigFloat(VRConfigFloat config, float value) { + vrConfigFloat[config] = value; +} + +void* VR_BindFramebuffer(engine_t *engine) { + if (!initialized) return nullptr; + int fboIndex = VR_GetConfig(VR_CONFIG_CURRENT_FBO); + return ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]); +} + +XrView VR_GetView(int eye) { + return projections[eye]; } diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index e19a0e82a5..78de6a5ccf 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -5,15 +5,7 @@ enum VRConfig { //switching between 2D and 3D - VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D, - //camera setup - VR_CONFIG_FOV_SCALE, VR_CONFIG_CANVAS_DISTANCE, - //6DoF - VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE, VR_CONFIG_6DOF_PRECISE, - VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z, - VR_CONFIG_MIRROR_PITCH, VR_CONFIG_MIRROR_YAW, VR_CONFIG_MIRROR_ROLL, - //2D canvas positioning - VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, + VR_CONFIG_MODE, //mouse cursor VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y, //viewport setup @@ -25,18 +17,19 @@ enum VRConfig { VR_CONFIG_MAX }; -enum VRMatrix { - VR_PROJECTION_MATRIX_LEFT_EYE, - VR_PROJECTION_MATRIX_RIGHT_EYE, - VR_VIEW_MATRIX_LEFT_EYE, - VR_VIEW_MATRIX_RIGHT_EYE, - VR_MATRIX_COUNT +enum VRConfigFloat { + // 2D canvas positioning + VR_CONFIG_CANVAS_DISTANCE, VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, + VR_CONFIG_CANVAS_ASPECT, + + VR_CONFIG_FLOAT_MAX }; enum VRMode { - VR_MODE_FLAT_SCREEN = 0, - VR_MODE_MONO_6DOF = 1, - VR_MODE_STEREO_6DOF = 2 + VR_MODE_MONO_SCREEN, + VR_MODE_STEREO_SCREEN, + VR_MODE_MONO_6DOF, + VR_MODE_STEREO_6DOF }; void VR_GetResolution( engine_t* engine, int *pWidth, int *pHeight ); @@ -50,6 +43,8 @@ void VR_FinishFrame( engine_t* engine ); int VR_GetConfig( VRConfig config ); void VR_SetConfig( VRConfig config, int value); +float VR_GetConfigFloat( VRConfigFloat config ); +void VR_SetConfigFloat( VRConfigFloat config, float value ); -void VR_BindFramebuffer(engine_t *engine); -ovrMatrix4f VR_GetMatrix( VRMatrix matrix ); +void* VR_BindFramebuffer(engine_t *engine); +XrView VR_GetView(int eye); diff --git a/Common/VR/VRTweaks.cpp b/Common/VR/VRTweaks.cpp deleted file mode 100644 index 209ef56b6d..0000000000 --- a/Common/VR/VRTweaks.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "VRTweaks.h" -#include - -bool VR_TweakIsMatrixBigScale(float* matrix) { - for (int i = 0; i < 2; i++) { - float value = matrix[i * 4 + i]; - if (fabs(value) < 10.0f) return false; - } - return true; -} - -bool VR_TweakIsMatrixIdentity(float* matrix) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - float value = matrix[i * 4 + j]; - - // Other number than zero on non-diagonale - if ((i != j) && (fabs(value) > EPSILON)) return false; - // Other number than one on diagonale - if ((i == j) && (fabs(value - 1.0f) > EPSILON)) return false; - } - } - return true; -} - -bool VR_TweakIsMatrixOneOrtho(float* matrix) { - float value = matrix[15]; - return fabs(value - 1) < EPSILON; -} - -bool VR_TweakIsMatrixOneScale(float* matrix) { - for (int i = 0; i < 2; i++) { - float value = matrix[i * 4 + i]; - if (fabs(value - 1) > EPSILON) return false; - } - return true; -} - -bool VR_TweakIsMatrixOneTransform(float* matrix) { - for (int j = 0; j < 4; j++) { - float value = matrix[12 + j]; - if (fabs(fabs(value) - 1.0f) > EPSILON) return false; - } - return true; -} - -void VR_TweakMirroring(float* projMatrix) { - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_X, projMatrix[0] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Y, projMatrix[5] < 0); - VR_SetConfig(VR_CONFIG_MIRROR_AXIS_Z, projMatrix[10] > 0); - if ((projMatrix[0] < 0) && (projMatrix[10] < 0)) { //e.g. Dante's inferno - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else if (projMatrix[10] < 0) { //e.g. GTA - Liberty city - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, false); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else if (projMatrix[5] < 0) { //e.g. PES 2014 - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, true); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, false); - } else { //e.g. Lego Pirates - VR_SetConfig(VR_CONFIG_MIRROR_PITCH, false); - VR_SetConfig(VR_CONFIG_MIRROR_YAW, true); - VR_SetConfig(VR_CONFIG_MIRROR_ROLL, true); - } -} - -void VR_TweakProjection(float* src, float* dst, VRMatrix matrix) { - ovrMatrix4f hmdProjection = VR_GetMatrix(matrix); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if ((hmdProjection.M[i][j] > 0) != (src[i * 4 + j] > 0)) { - hmdProjection.M[i][j] *= -1.0f; - } - } - } - memcpy(dst, hmdProjection.M, 16 * sizeof(float)); -} - -void VR_TweakView(float* view, VRMatrix matrix) { - // Get view matrix from the game - ovrMatrix4f gameView; - memcpy(gameView.M, view, 16 * sizeof(float)); - - // Get view matrix from the headset - ovrMatrix4f hmdView = VR_GetMatrix(matrix); - - // Combine the matrices - ovrMatrix4f renderView = ovrMatrix4f_Multiply(&hmdView, &gameView); - memcpy(view, renderView.M, 16 * sizeof(float)); -} diff --git a/Common/VR/VRTweaks.h b/Common/VR/VRTweaks.h deleted file mode 100644 index 173314a86f..0000000000 --- a/Common/VR/VRTweaks.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "VRRenderer.h" - -bool VR_TweakIsMatrixBigScale(float* matrix); -bool VR_TweakIsMatrixIdentity(float* matrix); -bool VR_TweakIsMatrixOneOrtho(float* matrix); -bool VR_TweakIsMatrixOneScale(float* matrix); -bool VR_TweakIsMatrixOneTransform(float* matrix); -void VR_TweakMirroring(float* projMatrix); -void VR_TweakProjection(float* src, float* dst, VRMatrix matrix); -void VR_TweakView(float* view, VRMatrix matrix); diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index 50887f18bf..b52a81f35b 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -278,6 +278,19 @@ inline OpArg MRegSum(X64Reg base, X64Reg offset) return MComplex(base, offset, 1, 0); } +template +inline bool Accessible(const T *t1, const T *t2) { + ptrdiff_t diff = (const uint8_t *)t1 - (const uint8_t *)t2; + return diff > -0x7FFFFFE0 && diff < 0x7FFFFFE0; +} + +template +inline OpArg MAccessibleDisp(X64Reg r, const T *tbase, const T *t) { + _assert_(Accessible(tbase, t)); + ptrdiff_t diff = (const uint8_t *)t - (const uint8_t *)tbase; + return MDisp(r, (int)diff); +} + inline OpArg Imm8 (u8 imm) {return OpArg(imm, SCALE_IMM8);} inline OpArg Imm16(u16 imm) {return OpArg(imm, SCALE_IMM16);} //rarely used inline OpArg Imm32(u32 imm) {return OpArg(imm, SCALE_IMM32);} diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 08fb82d91e..fcc61a2176 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -17,6 +17,7 @@ #include +#include "Common/Log.h" #include "Common/Data/Format/IniFile.h" #include "Common/StringUtils.h" #include "Core/Compatibility.h" @@ -42,21 +43,29 @@ void Compatibility::Load(const std::string &gameID) { } } + { + IniFile compat2; + // This one is user-editable. Need to load it after the system one. + Path path = GetSysDirectory(DIRECTORY_SYSTEM) / "compat.ini"; + if (compat2.Load(path.ToString())) { + CheckSettings(compat2, gameID); + } + } + { IniFile compat; // This loads from assets. if (compat.LoadFromVFS("compatvr.ini")) { - CheckSetting(compat, gameID, "Skyplane", &vrCompat_.Skyplane); - CheckSetting(compat, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); + CheckVRSettings(compat, gameID); } } { IniFile compat2; // This one is user-editable. Need to load it after the system one. - Path path = GetSysDirectory(DIRECTORY_SYSTEM) / "compat.ini"; + Path path = GetSysDirectory(DIRECTORY_SYSTEM) / "compatvr.ini"; if (compat2.Load(path.ToString())) { - CheckSettings(compat2, gameID); + CheckVRSettings(compat2, gameID); } } } @@ -107,9 +116,23 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "DeswizzleDepth", &flags_.DeswizzleDepth); CheckSetting(iniFile, gameID, "SplitFramebufferMargin", &flags_.SplitFramebufferMargin); CheckSetting(iniFile, gameID, "ForceLowerResolutionForEffectsOn", &flags_.ForceLowerResolutionForEffectsOn); + CheckSetting(iniFile, gameID, "ForceLowerResolutionForEffectsOff", &flags_.ForceLowerResolutionForEffectsOff); CheckSetting(iniFile, gameID, "AllowDownloadCLUT", &flags_.AllowDownloadCLUT); CheckSetting(iniFile, gameID, "NearestFilteringOnFramebufferCreate", &flags_.NearestFilteringOnFramebufferCreate); - CheckSetting(iniFile, gameID, "Fontltn12Hack", &flags_.Fontltn12Hack); + CheckSetting(iniFile, gameID, "SecondaryTextureCache", &flags_.SecondaryTextureCache); + CheckSetting(iniFile, gameID, "EnglishOrJapaneseOnly", &flags_.EnglishOrJapaneseOnly); + CheckSetting(iniFile, gameID, "OldAdrenoPixelDepthRoundingGL", &flags_.OldAdrenoPixelDepthRoundingGL); + CheckSetting(iniFile, gameID, "ForceCircleButtonConfirm", &flags_.ForceCircleButtonConfirm); + CheckSetting(iniFile, gameID, "DisallowFramebufferAtOffset", &flags_.DisallowFramebufferAtOffset); + CheckSetting(iniFile, gameID, "Fontltn12Hack", &flags_.Fontltn12Hack); +} + +void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { + CheckSetting(iniFile, gameID, "IdentityViewHack", &vrCompat_.IdentityViewHack); + CheckSetting(iniFile, gameID, "Skyplane", &vrCompat_.Skyplane); + CheckSetting(iniFile, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); + + NOTICE_LOG(G3D, "UnitsPerMeter for %s: %f", gameID.c_str(), vrCompat_.UnitsPerMeter); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 13fbec305c..05c8de3a05 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -87,12 +87,19 @@ struct CompatFlags { bool DeswizzleDepth; bool SplitFramebufferMargin; bool ForceLowerResolutionForEffectsOn; + bool ForceLowerResolutionForEffectsOff; bool AllowDownloadCLUT; bool NearestFilteringOnFramebufferCreate; - bool Fontltn12Hack; + bool SecondaryTextureCache; + bool EnglishOrJapaneseOnly; + bool OldAdrenoPixelDepthRoundingGL; + bool ForceCircleButtonConfirm; + bool DisallowFramebufferAtOffset; + bool Fontltn12Hack; }; struct VRCompat { + bool IdentityViewHack; bool Skyplane; float UnitsPerMeter; }; @@ -115,6 +122,7 @@ public: private: void Clear(); void CheckSettings(IniFile &iniFile, const std::string &gameID); + void CheckVRSettings(IniFile &iniFile, const std::string &gameID); void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag); void CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, float *value); diff --git a/Core/Config.cpp b/Core/Config.cpp index 650e1812fa..ad93c3aef2 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -257,7 +257,7 @@ struct ConfigSetting { return type_ != TYPE_TERMINATOR; } - bool Get(Section *section) { + bool Get(const Section *section) { switch (type_) { case TYPE_BOOL: if (cb_.b) { @@ -516,6 +516,10 @@ static bool DefaultEnableStateUndo() { return true; } +static float DefaultUISaturation() { + return IsVREnabled() ? 1.5f : 1.0f; +} + struct ConfigSectionSettings { const char *section; ConfigSetting *settings; @@ -597,7 +601,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("BackgroundAnimation", &g_Config.iBackgroundAnimation, 1, true, false), ConfigSetting("UITint", &g_Config.fUITint, 0.0, true, false), - ConfigSetting("UISaturation", &g_Config.fUISaturation, 1.0, true, false), + ConfigSetting("UISaturation", &g_Config.fUISaturation, &DefaultUISaturation, true, false), #if defined(USING_WIN_UI) ConfigSetting("TopMost", &g_Config.bTopMost, false), @@ -644,6 +648,9 @@ static int DefaultInternalResolution() { #if defined(USING_WIN_UI) || defined(USING_QT_UI) return 0; #else + if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { + return 4; + } int longestDisplaySide = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)); int scale = longestDisplaySide >= 1000 ? 2 : 1; INFO_LOG(G3D, "Longest display side: %d pixels. Choosing scale %d", longestDisplaySide, scale); @@ -659,10 +666,6 @@ static int DefaultFastForwardMode() { #endif } -static int DefaultZoomType() { - return (int)SmallDisplayZoom::AUTO; -} - static int DefaultAndroidHwScale() { #ifdef __ANDROID__ if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19 || System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) { @@ -697,7 +700,7 @@ const char * const vulkanDefaultBlacklist[] = { }; static int DefaultGPUBackend() { - if (IsVRBuild()) { + if (IsVREnabled()) { return (int)GPUBackend::OPENGL; } @@ -874,8 +877,8 @@ static ConfigSetting graphicsSettings[] = { #endif ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false), ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false), - ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, true, true, true), - ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, 1, true, true), + ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, false, true, true), + ReportedConfigSetting("SkipBufferEffects", &g_Config.bSkipBufferEffects, false, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ConfigSetting("SoftwareRendererJit", &g_Config.bSoftwareRenderingJit, true, true, true), ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true), @@ -887,7 +890,9 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true), ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), ReportedConfigSetting("FrameSkipType", &g_Config.iFrameSkipType, 0, true, true), - ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), + ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, IsVREnabled(), true, true), + ConfigSetting("StereoRendering", &g_Config.bStereoRendering, false, true, true), + ConfigSetting("StereoToMonoShader", &g_Config.sStereoToMonoShader, "RedBlue", true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), ConfigSetting("AnalogFrameRate", &g_Config.iAnalogFpsLimit, 240, true, true), @@ -899,10 +904,10 @@ static ConfigSetting graphicsSettings[] = { // Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine. ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true), + ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 0, true, true), // Number of samples is 1 << iMultiSampleLevel ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, true, true), ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true), - ReportedConfigSetting("TextureSecondaryCache", &g_Config.bTextureSecondaryCache, false, true, true), ReportedConfigSetting("VertexDecJit", &g_Config.bVertexDecoderJit, &DefaultCodeGen, false), #ifndef MOBILE_DEVICE @@ -910,10 +915,12 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("FullScreenMulti", &g_Config.bFullScreenMulti, false), #endif - ConfigSetting("SmallDisplayZoomType", &g_Config.iSmallDisplayZoomType, &DefaultZoomType, true, true), - ConfigSetting("SmallDisplayOffsetX", &g_Config.fSmallDisplayOffsetX, 0.5f, true, true), - ConfigSetting("SmallDisplayOffsetY", &g_Config.fSmallDisplayOffsetY, 0.5f, true, true), - ConfigSetting("SmallDisplayZoomLevel", &g_Config.fSmallDisplayZoomLevel, 1.0f, true, true), + ConfigSetting("DisplayOffsetX", &g_Config.fDisplayOffsetX, 0.5f, true, true), + ConfigSetting("DisplayOffsetY", &g_Config.fDisplayOffsetY, 0.5f, true, true), + ConfigSetting("DisplayScale", &g_Config.fDisplayScale, 1.0f, true, true), + ConfigSetting("DisplayAspectRatio", &g_Config.fDisplayAspectRatio, 1.0f, true, true), + ConfigSetting("DisplayStretch", &g_Config.bDisplayStretch, false, true, true), + ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, true, true, true), ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true), ConfigSetting("IgnoreScreenInsets", &g_Config.bIgnoreScreenInsets, true, true, false), @@ -936,7 +943,7 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("TextureShader", &g_Config.sTextureShaderName, "Off", true, true), ConfigSetting("ShaderChainRequires60FPS", &g_Config.bShaderChainRequires60FPS, false, true, true), - ReportedConfigSetting("MemBlockTransferGPU", &g_Config.bBlockTransferGPU, true, true, true), + ReportedConfigSetting("SkipGPUReadbacks", &g_Config.bSkipGPUReadbacks, false, true, true), ConfigSetting("GfxDebugOutput", &g_Config.bGfxDebugOutput, false, false, false), ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, true, false), @@ -1120,9 +1127,10 @@ static int DefaultSystemParamLanguage() { int defaultLang = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; if (g_Config.bFirstRun) { // TODO: Be smart about same language, different country - auto langValuesMapping = GetLangValuesMapping(); - if (langValuesMapping.find(g_Config.sLanguageIni) != langValuesMapping.end()) { - defaultLang = langValuesMapping[g_Config.sLanguageIni].second; + auto &langValuesMapping = g_Config.GetLangValuesMapping(); + auto iter = langValuesMapping.find(g_Config.sLanguageIni); + if (iter != langValuesMapping.end()) { + defaultLang = iter->second.second; } } return defaultLang; @@ -1206,8 +1214,15 @@ static ConfigSetting vrSettings[] = { ConfigSetting("VREnable", &g_Config.bEnableVR, true), ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false), - ConfigSetting("VRCanvasDistance", &g_Config.iCanvasDistance, 6), - ConfigSetting("VRFieldOfView", &g_Config.iFieldOfViewPercentage, 100), + ConfigSetting("VREnableMotions", &g_Config.bEnableMotions, true), + ConfigSetting("VRbForce72Hz", &g_Config.bForce72Hz, true), + ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f), + ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f), + ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f), + ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 12.0f), + ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f), + ConfigSetting("VRHeadUpDisplayScale", &g_Config.fHeadUpDisplayScale, 0.3f), + ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f), ConfigSetting(false), }; @@ -1262,14 +1277,12 @@ Config::~Config() { delete private_; } -std::map> GetLangValuesMapping() { - std::map> langValuesMapping; +void Config::LoadLangValuesMapping() { IniFile mapping; mapping.LoadFromVFS("langregion.ini"); std::vector keys; mapping.GetKeys("LangRegionNames", keys); - std::map langCodeMapping; langCodeMapping["JAPANESE"] = PSP_SYSTEMPARAM_LANGUAGE_JAPANESE; langCodeMapping["ENGLISH"] = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; @@ -1284,8 +1297,8 @@ std::map> GetLangValuesMapping() { langCodeMapping["CHINESE_TRADITIONAL"] = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; langCodeMapping["CHINESE_SIMPLIFIED"] = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; - Section *langRegionNames = mapping.GetOrCreateSection("LangRegionNames"); - Section *systemLanguage = mapping.GetOrCreateSection("SystemLanguage"); + const Section *langRegionNames = mapping.GetOrCreateSection("LangRegionNames"); + const Section *systemLanguage = mapping.GetOrCreateSection("SystemLanguage"); for (size_t i = 0; i < keys.size(); i++) { std::string langName; @@ -1295,9 +1308,15 @@ std::map> GetLangValuesMapping() { int iLangCode = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; if (langCodeMapping.find(langCode) != langCodeMapping.end()) iLangCode = langCodeMapping[langCode]; - langValuesMapping[keys[i]] = std::make_pair(langName, iLangCode); + langValuesMapping_[keys[i]] = std::make_pair(langName, iLangCode); } - return langValuesMapping; +} + +const std::map> &Config::GetLangValuesMapping() { + if (langValuesMapping_.empty()) { + LoadLangValuesMapping(); + } + return langValuesMapping_; } void Config::Reload() { @@ -1310,9 +1329,11 @@ void Config::Reload() { // really think of any other legit uses). void Config::UpdateIniLocation(const char *iniFileName, const char *controllerIniFilename) { const bool useIniFilename = iniFileName != nullptr && strlen(iniFileName) > 0; - iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : "ppsspp.ini"); + const char *ppssppIniFilename = IsVREnabled() ? "ppssppvr.ini" : "ppsspp.ini"; + iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : ppssppIniFilename); const bool useControllerIniFilename = controllerIniFilename != nullptr && strlen(controllerIniFilename) > 0; - controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : "controls.ini"); + const char *controlsIniFilename = IsVREnabled() ? "controlsvr.ini" : "controls.ini"; + controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : controlsIniFilename); } void Config::Load(const char *iniFileName, const char *controllerIniFilename) { @@ -1386,15 +1407,27 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } } - auto postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting")->ToMap(); + // Default values for post process shaders + bool postShadersInitialized = iniFile.HasSection("PostShaderList"); + Section *postShaderChain = iniFile.GetOrCreateSection("PostShaderList"); + Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); + if (IsVREnabled() && !postShadersInitialized) { + postShaderChain->Set("PostShader1", "ColorCorrection"); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue1", 1.0f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue2", 1.5f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue3", 1.1f); + postShaderSetting->Set("ColorCorrectionSettingCurrentValue4", 1.0f); + } + + // Load post process shader values mPostShaderSetting.clear(); - for (auto it : postShaderSetting) { + for (const auto& it : postShaderSetting->ToMap()) { mPostShaderSetting[it.first] = std::stof(it.second); } - auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + // Load post process shader names vPostShaderNames.clear(); - for (auto it : postShaderChain) { + for (const auto& it : postShaderChain->ToMap()) { if (it.second != "Off") vPostShaderNames.push_back(it.second); } @@ -1403,9 +1436,6 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (iAnisotropyLevel > 4) { iAnisotropyLevel = 4; } - if (iRenderingMode != FB_NON_BUFFERED_MODE && iRenderingMode != FB_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; - } // Check for an old dpad setting Section *control = iniFile.GetOrCreateSection("Control"); @@ -1456,14 +1486,14 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (sMACAddress.length() != 17) sMACAddress = CreateRandMAC(); - if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; + if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; } // Override ppsspp.ini JIT value to prevent crashing if (DefaultCpuCore() != (int)CPUCore::JIT && g_Config.iCpuCore == (int)CPUCore::JIT) { jitForcedOff = true; - g_Config.iCpuCore = (int)CPUCore::INTERPRETER; + g_Config.iCpuCore = (int)CPUCore::IR_JIT; } // Automatically silence secondary instances. Could be an option I guess, but meh. @@ -1585,11 +1615,8 @@ bool Config::Save(const char *saveReason) { } if (jitForcedOff) { // force JIT off again just in case Config::Save() is called without exiting PPSSPP -#if PPSSPP_PLATFORM(IOS) - g_Config.iCpuCore = (int)CPUCore::IR_JIT; -#else - g_Config.iCpuCore = (int)CPUCore::INTERPRETER; -#endif + if (g_Config.iCpuCore != (int)CPUCore::INTERPRETER) + g_Config.iCpuCore = (int)CPUCore::IR_JIT; } return true; } @@ -1811,7 +1838,8 @@ bool Config::deleteGameConfig(const std::string& pGameId) { } Path Config::getGameConfigFile(const std::string &pGameId) { - std::string iniFileName = pGameId + "_ppsspp.ini"; + const char *ppssppIniFilename = IsVREnabled() ? "_ppssppvr.ini" : "_ppsspp.ini"; + std::string iniFileName = pGameId + ppssppIniFilename; Path iniFileNameFull = FindConfigFile(iniFileName); return iniFileNameFull; @@ -1978,5 +2006,5 @@ void Config::GetReportingInfo(UrlEncoder &data) { } bool Config::IsPortrait() const { - return (iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180) && iRenderingMode != FB_NON_BUFFERED_MODE; + return (iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180) && !bSkipBufferEffects; } diff --git a/Core/Config.h b/Core/Config.h index 10748583a9..64d17da3a1 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -162,18 +162,23 @@ public: bool bSoftwareRendering; bool bSoftwareRenderingJit; bool bHardwareTransform; // only used in the GLES backend - bool bSoftwareSkinning; // may speed up some games + bool bSoftwareSkinning; bool bVendorBugChecksEnabled; bool bUseGeometryShader; - int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering + // Speedhacks (more will be moved here): + bool bSkipBufferEffects; + int iTexFiltering; // 1 = auto , 2 = nearest , 3 = linear , 4 = auto max quality int iBufFilter; // 1 = linear, 2 = nearest - int iSmallDisplayZoomType; // Used to fit display into screen 0 = stretch, 1 = partial stretch, 2 = auto scaling, 3 = manual scaling. - float fSmallDisplayOffsetX; // Along with Y it goes from 0.0 to 1.0, XY (0.5, 0.5) = center of the screen - float fSmallDisplayOffsetY; - float fSmallDisplayZoomLevel; //This is used for zoom values, both in and out. - bool bImmersiveMode; // Mode on Android Kitkat 4.4 that hides the back button etc. + + bool bDisplayStretch; // Automatically matches the aspect ratio of the window. + float fDisplayOffsetX; + float fDisplayOffsetY; + float fDisplayScale; // Relative to the most constraining axis (x or y). + float fDisplayAspectRatio; // Stored relative to the PSP's native ratio, so 1.0 is the normal pixel aspect ratio. + + bool bImmersiveMode; // Mode on Android Kitkat 4.4 and later that hides the back button etc. bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations. bool bIgnoreScreenInsets; // Android: Center screen disregarding insets if this is enabled. bool bVSync; @@ -199,13 +204,13 @@ public: bool bVertexCache; bool bTextureBackoffCache; - bool bTextureSecondaryCache; bool bVertexDecoderJit; bool bFullScreen; bool bFullScreenMulti; int iForceFullScreen = -1; // -1 = nope, 0 = force off, 1 = force on (not saved.) int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso + int iMultiSampleLevel; int bHighQualityDepth; bool bReplaceTextures; bool bSaveNewTextures; @@ -234,13 +239,19 @@ public: float fCwCheatScrollPosition; float fGameListScrollPosition; int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive - bool bBlockTransferGPU; + bool bSkipGPUReadbacks; int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High bool bHardwareTessellation; bool bShaderCache; // Hidden ini-only setting, useful for debugging shader compile times. std::vector vPostShaderNames; // Off for chain end (only Off for no shader) std::map mPostShaderSetting; + + // Note that this is separate from VR stereo, though it'll share some code paths. + bool bStereoRendering; + // There can only be one, unlike regular post shaders. + std::string sStereoToMonoShader; + bool bShaderChainRequires60FPS; std::string sTextureShaderName; bool bGfxDebugOutput; @@ -457,8 +468,15 @@ public: bool bEnableVR; bool bEnable6DoF; bool bEnableStereo; - int iCanvasDistance; - int iFieldOfViewPercentage; + bool bEnableMotions; + bool bForce72Hz; + float fCameraDistance; + float fCameraHeight; + float fCameraSide; + float fCanvasDistance; + float fFieldOfViewPercentage; + float fHeadUpDisplayScale; + float fMotionLength; // Debugger int iDisasmWindowX; @@ -550,21 +568,24 @@ public: bool HasRecentIsos() const; void ClearRecentIsos(); + const std::map> &GetLangValuesMapping(); + protected: void LoadStandardControllerIni(); + void LoadLangValuesMapping(); private: bool reload_ = false; std::string gameId_; std::string gameIdTitle_; std::vector recentIsos; + std::map> langValuesMapping_; Path iniFilename_; Path controllerIniFilename_; Path searchPath_; ConfigPrivate *private_ = nullptr; }; -std::map> GetLangValuesMapping(); std::string CreateRandMAC(); // TODO: Find a better place for this. diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 9018653aab..f8e88be931 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -105,13 +105,6 @@ enum IOTimingMethods { IOTIMING_REALISTIC = 2, }; -enum class SmallDisplayZoom { - STRETCH = 0, - PARTIAL_STRETCH = 1, - AUTO = 2, - MANUAL = 3, -}; - enum class AutoLoadSaveState { OFF = 0, OLDEST = 1, diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index b19c29dbda..8cc14209d7 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -15,6 +15,7 @@ static float MapAxisValue(float v) { const float invDeadzone = g_Config.fAnalogInverseDeadzone; const float sensitivity = g_Config.fAnalogSensitivity; const float sign = v >= 0.0f ? 1.0f : -1.0f; + return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f); } @@ -49,24 +50,46 @@ void ControlMapper::SetRawCallback(std::function setRaw setRawAnalog_ = setRawAnalog; } - -void ControlMapper::SetPSPAxis(char axis, float value, int stick) { - static float history[2][2] = {}; - +void ControlMapper::SetPSPAxis(int device, char axis, float value, int stick) { int axisId = axis == 'X' ? 0 : 1; - history[stick][axisId] = value; + float position[2]; + position[0] = history[stick][0]; + position[1] = history[stick][1]; - float x = history[stick][0]; - float y = history[stick][1]; + position[axisId] = value; + + float x = position[0]; + float y = position[1]; if (setRawAnalog_) { setRawAnalog_(stick, x, y); } - ConvertAnalogStick(x, y); + // NOTE: We need to use single-axis checks, since the other axis might be from another device, + // so we'll add a little leeway. + bool inDeadZone = fabsf(value) < g_Config.fAnalogDeadzone * 0.7f; - setPSPAnalog_(stick, x, y); + bool ignore = false; + + if (inDeadZone && lastNonDeadzoneDeviceID_[stick] != device) { + // Ignore this event! See issue #15465 + ignore = true; + } + + if (!inDeadZone) { + lastNonDeadzoneDeviceID_[stick] = device; + } + + if (!ignore) { + history[stick][axisId] = value; + + float x = history[stick][0]; + float y = history[stick][1]; + + ConvertAnalogStick(x, y); + setPSPAnalog_(stick, x, y); + } } bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) { @@ -79,7 +102,7 @@ bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) { } for (size_t i = 0; i < pspKeys.size(); i++) { - pspKey(pspKeys[i], key.flags); + pspKey(key.deviceId, pspKeys[i], key.flags); } DEBUG_LOG(SYSTEM, "Key: %d DeviceId: %d", key.keyCode, key.deviceId); @@ -155,7 +178,7 @@ static int RotatePSPKeyCode(int x) { } } -void ControlMapper::setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero) { +void ControlMapper::setVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero) { // The down events can repeat, so just trust the virtKeys array. bool minDown = virtKeys[virtualKeyMin - VIRTKEY_FIRST]; bool maxDown = virtKeys[virtualKeyMax - VIRTKEY_FIRST]; @@ -167,11 +190,11 @@ void ControlMapper::setVKeyAnalog(char axis, int stick, int virtualKeyMin, int v if (maxDown) value += scale; if (setZero || minDown || maxDown) { - SetPSPAxis(axis, value, stick); + SetPSPAxis(deviceId, axis, value, stick); } } -void ControlMapper::pspKey(int pspKeyCode, int flags) { +void ControlMapper::pspKey(int deviceId, int pspKeyCode, int flags) { int rotations = 0; switch (g_Config.iInternalScreenRotation) { case ROTATION_LOCKED_HORIZONTAL180: @@ -193,11 +216,11 @@ void ControlMapper::pspKey(int pspKeyCode, int flags) { int vk = pspKeyCode - VIRTKEY_FIRST; if (flags & KEY_DOWN) { virtKeys[vk] = true; - onVKeyDown(pspKeyCode); + onVKeyDown(deviceId, pspKeyCode); } if (flags & KEY_UP) { virtKeys[vk] = false; - onVKeyUp(pspKeyCode); + onVKeyUp(deviceId, pspKeyCode); } } else { // INFO_LOG(SYSTEM, "pspKey %i %i", pspKeyCode, flags); @@ -208,32 +231,32 @@ void ControlMapper::pspKey(int pspKeyCode, int flags) { } } -void ControlMapper::onVKeyDown(int vkey) { +void ControlMapper::onVKeyDown(int deviceId, int vkey) { switch (vkey) { case VIRTKEY_AXIS_X_MIN: case VIRTKEY_AXIS_X_MAX: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); break; case VIRTKEY_AXIS_Y_MIN: case VIRTKEY_AXIS_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); break; case VIRTKEY_AXIS_RIGHT_X_MIN: case VIRTKEY_AXIS_RIGHT_X_MAX: - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); break; case VIRTKEY_AXIS_RIGHT_Y_MIN: case VIRTKEY_AXIS_RIGHT_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); break; case VIRTKEY_ANALOG_LIGHTLY: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); break; case VIRTKEY_ANALOG_ROTATE_CW: @@ -252,32 +275,32 @@ void ControlMapper::onVKeyDown(int vkey) { } } -void ControlMapper::onVKeyUp(int vkey) { +void ControlMapper::onVKeyUp(int deviceId, int vkey) { switch (vkey) { case VIRTKEY_AXIS_X_MIN: case VIRTKEY_AXIS_X_MAX: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX); break; case VIRTKEY_AXIS_Y_MIN: case VIRTKEY_AXIS_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX); break; case VIRTKEY_AXIS_RIGHT_X_MIN: case VIRTKEY_AXIS_RIGHT_X_MAX: - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX); break; case VIRTKEY_AXIS_RIGHT_Y_MIN: case VIRTKEY_AXIS_RIGHT_Y_MAX: - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX); break; case VIRTKEY_ANALOG_LIGHTLY: - setVKeyAnalog('X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); - setVKeyAnalog('X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); - setVKeyAnalog('Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_LEFT, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_LEFT, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX, false); + setVKeyAnalog(deviceId, 'X', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, false); + setVKeyAnalog(deviceId, 'Y', CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX, false); break; case VIRTKEY_ANALOG_ROTATE_CW: @@ -312,29 +335,29 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { float value = fabs(axis.value) * scale; switch (result) { case VIRTKEY_AXIS_X_MIN: - SetPSPAxis('X', -value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_X_MAX: - SetPSPAxis('X', value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_Y_MIN: - SetPSPAxis('Y', -value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_Y_MAX: - SetPSPAxis('Y', value, CTRL_STICK_LEFT); + SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_LEFT); break; case VIRTKEY_AXIS_RIGHT_X_MIN: - SetPSPAxis('X', -value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'X', -value, CTRL_STICK_RIGHT); break; case VIRTKEY_AXIS_RIGHT_X_MAX: - SetPSPAxis('X', value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'X', value, CTRL_STICK_RIGHT); break; case VIRTKEY_AXIS_RIGHT_Y_MIN: - SetPSPAxis('Y', -value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'Y', -value, CTRL_STICK_RIGHT); break; case VIRTKEY_AXIS_RIGHT_Y_MAX: - SetPSPAxis('Y', value, CTRL_STICK_RIGHT); + SetPSPAxis(axis.deviceId, 'Y', value, CTRL_STICK_RIGHT); break; case VIRTKEY_SPEED_ANALOG: @@ -366,22 +389,22 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { if (axisState != 0) { for (size_t i = 0; i < results.size(); i++) { if (!IsAnalogStickKey(results[i])) - pspKey(results[i], KEY_DOWN); + pspKey(axis.deviceId, results[i], KEY_DOWN); } // Also unpress the other direction (unless both directions press the same key.) for (size_t i = 0; i < resultsOpposite.size(); i++) { if (!IsAnalogStickKey(resultsOpposite[i]) && std::find(results.begin(), results.end(), resultsOpposite[i]) == results.end()) - pspKey(resultsOpposite[i], KEY_UP); + pspKey(axis.deviceId, resultsOpposite[i], KEY_UP); } } else if (axisState == 0) { // Release both directions, trying to deal with some erratic controllers that can cause it to stick. for (size_t i = 0; i < results.size(); i++) { if (!IsAnalogStickKey(results[i])) - pspKey(results[i], KEY_UP); + pspKey(axis.deviceId, results[i], KEY_UP); } for (size_t i = 0; i < resultsOpposite.size(); i++) { if (!IsAnalogStickKey(resultsOpposite[i])) - pspKey(resultsOpposite[i], KEY_UP); + pspKey(axis.deviceId, resultsOpposite[i], KEY_UP); } } } diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index d930c56f8b..f837bc73c0 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -16,7 +16,7 @@ public: void Update(); bool Key(const KeyInput &key, bool *pauseTrigger); - void pspKey(int pspKeyCode, int flags); + void pspKey(int deviceId, int pspKeyCode, int flags); bool Axis(const AxisInput &axis); // Required callbacks @@ -30,13 +30,13 @@ public: private: void processAxis(const AxisInput &axis, int direction); - void setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); + void setVKeyAnalog(int deviceId, char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); - void SetPSPAxis(char axis, float value, int stick); + void SetPSPAxis(int deviceId, char axis, float value, int stick); void ProcessAnalogSpeed(const AxisInput &axis, bool opposite); - void onVKeyDown(int vkey); - void onVKeyUp(int vkey); + void onVKeyDown(int deviceId, int vkey); + void onVKeyUp(int deviceId, int vkey); // To track mappable virtual keys. We can have as many as we want. bool virtKeys[VIRTKEY_COUNT]{}; @@ -44,6 +44,10 @@ private: // De-noise mapped axis updates int axisState_[JOYSTICK_AXIS_MAX]{}; + int lastNonDeadzoneDeviceID_[2]{}; + + float history[2][2] = {}; + // Mappable auto-rotation. Useful for keyboard/dpad->analog in a few games. bool autoRotatingAnalogCW_ = false; bool autoRotatingAnalogCCW_ = false; diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 6f5dc789a2..14dc27d86f 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -962,7 +962,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames); if (op.PostShaderUniform.shader < shaderChain.size()) { std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = op.PostShaderUniform.value.f; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = op.PostShaderUniform.value.f; } } break; @@ -979,16 +979,16 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; switch (op.PostShaderUniform.format) { case 0: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x000000FF; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x000000FF; break; case 1: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x0000FFFF; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u & 0x0000FFFF; break; case 2: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.u; break; case 3: - g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.f; + g_Config.mPostShaderSetting[StringFromFormat("%sSettingCurrentValue%d", shaderName.c_str(), op.PostShaderUniform.uniform + 1)] = value.f; break; } } diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index ad1d37e41d..5ce977ec45 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -31,6 +31,7 @@ #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/CoreTiming.h" +std::atomic anyBreakPoints_(false); std::atomic anyMemChecks_(false); static std::mutex breakPointsMutex_; @@ -160,6 +161,8 @@ size_t CBreakPoints::FindMemCheck(u32 start, u32 end) bool CBreakPoints::IsAddressBreakPoint(u32 addr) { + if (!anyBreakPoints_) + return false; std::lock_guard guard(breakPointsMutex_); size_t bp = FindBreakpoint(addr); return bp != INVALID_BREAKPOINT && breakPoints_[bp].result != BREAK_ACTION_IGNORE; @@ -167,6 +170,8 @@ bool CBreakPoints::IsAddressBreakPoint(u32 addr) bool CBreakPoints::IsAddressBreakPoint(u32 addr, bool* enabled) { + if (!anyBreakPoints_) + return false; std::lock_guard guard(breakPointsMutex_); size_t bp = FindBreakpoint(addr); if (bp == INVALID_BREAKPOINT) return false; @@ -184,6 +189,8 @@ bool CBreakPoints::IsTempBreakPoint(u32 addr) bool CBreakPoints::RangeContainsBreakPoint(u32 addr, u32 size) { + if (!anyBreakPoints_) + return false; std::lock_guard guard(breakPointsMutex_); const u32 end = addr + size; for (const auto &bp : breakPoints_) @@ -207,6 +214,7 @@ void CBreakPoints::AddBreakPoint(u32 addr, bool temp) pt.addr = addr; breakPoints_.push_back(pt); + anyBreakPoints_ = true; guard.unlock(); Update(addr); } @@ -232,6 +240,7 @@ void CBreakPoints::RemoveBreakPoint(u32 addr) if (bp != INVALID_BREAKPOINT) breakPoints_.erase(breakPoints_.begin() + bp); + anyBreakPoints_ = !breakPoints_.empty(); guard.unlock(); Update(addr); } @@ -267,6 +276,8 @@ void CBreakPoints::ChangeBreakPoint(u32 addr, BreakAction result) void CBreakPoints::ClearAllBreakPoints() { + if (!anyBreakPoints_) + return; std::unique_lock guard(breakPointsMutex_); if (!breakPoints_.empty()) { @@ -278,9 +289,9 @@ void CBreakPoints::ClearAllBreakPoints() void CBreakPoints::ClearTemporaryBreakPoints() { - std::unique_lock guard(breakPointsMutex_); - if (breakPoints_.empty()) + if (!anyBreakPoints_) return; + std::unique_lock guard(breakPointsMutex_); bool update = false; for (int i = (int)breakPoints_.size()-1; i >= 0; --i) @@ -342,6 +353,8 @@ void CBreakPoints::ChangeBreakPointLogFormat(u32 addr, const std::string &fmt) { } BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { + if (!anyBreakPoints_) + return BREAK_ACTION_IGNORE; std::unique_lock guard(breakPointsMutex_); size_t bp = FindBreakpoint(addr, false); if (bp != INVALID_BREAKPOINT) { @@ -633,10 +646,12 @@ const std::vector CBreakPoints::GetBreakpoints() return breakPoints_; } -bool CBreakPoints::HasMemChecks() -{ - std::lock_guard guard(memCheckMutex_); - return !memChecks_.empty(); +bool CBreakPoints::HasBreakPoints() { + return anyBreakPoints_; +} + +bool CBreakPoints::HasMemChecks() { + return anyMemChecks_; } void CBreakPoints::Update(u32 addr) { diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index c2a7d81b6a..b60858e79e 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -115,7 +115,7 @@ struct MemCheck { // BreakPoints cannot overlap, only one is allowed per address. // MemChecks can overlap, as long as their ends are different. -// WARNING: MemChecks are not used in the interpreter or HLE currently. +// WARNING: MemChecks are not always tracked in HLE currently. class CBreakPoints { public: @@ -167,6 +167,7 @@ public: static const std::vector GetMemChecks(); static const std::vector GetBreakpoints(); + static bool HasBreakPoints(); static bool HasMemChecks(); static void Update(u32 addr = 0); diff --git a/Core/Debugger/DebugInterface.h b/Core/Debugger/DebugInterface.h index 6f48c7db0f..5422dc5798 100644 --- a/Core/Debugger/DebugInterface.h +++ b/Core/Debugger/DebugInterface.h @@ -23,13 +23,7 @@ struct MemMap; -enum { - GPR_SIZE_32, - GPR_SIZE_64, -}; - -class DebugInterface -{ +class DebugInterface { public: virtual const char *disasm(unsigned int address, unsigned int align) {return "NODEBUGGER";} virtual int getInstructionSize(int instruction) {return 1;} @@ -50,16 +44,13 @@ public: virtual bool initExpression(const char* exp, PostfixExpression& dest) { return false; }; virtual bool parseExpression(PostfixExpression& exp, u32& dest) { return false; }; - virtual u32 GetHi() { return 0; }; virtual u32 GetLo() { return 0; }; virtual void SetHi(u32 val) { }; virtual void SetLo(u32 val) { }; virtual const char *GetName() = 0; - virtual int GetGPRSize() = 0; //32 or 64 virtual u32 GetGPR32Value(int reg) {return 0;} virtual void SetGPR32Value(int reg) {} - virtual void SetGPR64Value(int reg) {} virtual u32 GetPC() = 0; virtual void SetPC(u32 _pc) = 0; virtual u32 GetLR() {return GetPC();} @@ -69,11 +60,9 @@ public: virtual int GetNumRegsInCategory(int cat) {return 0;} virtual const char *GetCategoryName(int cat) {return 0;} virtual const char *GetRegName(int cat, int index) {return 0;} - virtual void PrintRegValue(int cat, int index, char *out) - { + virtual void PrintRegValue(int cat, int index, char *out) { sprintf(out,"%08X",GetGPR32Value(index)); } virtual u32 GetRegValue(int cat, int index) {return 0;} virtual void SetRegValue(int cat, int index, u32 value) {} - }; diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index ab0e10aa9b..667ba134ab 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -122,7 +122,7 @@ void parseDisasm(const char* disasm, char* opcode, char* arguments, bool insertS // parse symbol if (disasm == jumpAddress) { - u32 branchTarget; + u32 branchTarget = 0; sscanf(disasm+3,"%08x",&branchTarget); const std::string addressSymbol = g_symbolMap->GetLabelString(branchTarget); @@ -709,22 +709,8 @@ void DisassemblyFunction::load() case 0x2B: // sw macro = new DisassemblyMacro(opAddress); - int dataSize; - switch (nextInfo & MEMTYPE_MASK) { - case MEMTYPE_BYTE: - dataSize = 1; - break; - case MEMTYPE_HWORD: - dataSize = 2; - break; - case MEMTYPE_WORD: - case MEMTYPE_FLOAT: - dataSize = 4; - break; - case MEMTYPE_VQUAD: - dataSize = 16; - break; - default: + int dataSize = MIPSGetMemoryAccessSize(next); + if (dataSize == 0) { delete macro; return; } diff --git a/Core/Debugger/DisassemblyManager.h b/Core/Debugger/DisassemblyManager.h index 00ff46c6fc..81520818b1 100644 --- a/Core/Debugger/DisassemblyManager.h +++ b/Core/Debugger/DisassemblyManager.h @@ -99,8 +99,7 @@ private: class DisassemblyOpcode: public DisassemblyEntry { public: - DisassemblyOpcode(u32 _address, int _num): address(_address), num(_num) { }; - virtual ~DisassemblyOpcode() { }; + DisassemblyOpcode(u32 _address, int _num): address(_address), num(_num) { } void recheck() override { }; int getNumLines() override { return num; }; int getLineNum(u32 address, bool findStart) override { return (address - this->address) / 4; }; @@ -118,8 +117,7 @@ private: class DisassemblyMacro: public DisassemblyEntry { public: - DisassemblyMacro(u32 _address): address(_address) { }; - virtual ~DisassemblyMacro() { }; + DisassemblyMacro(u32 _address): address(_address) { } void setMacroLi(u32 _immediate, u8 _rt); void setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize); @@ -147,7 +145,6 @@ class DisassemblyData: public DisassemblyEntry { public: DisassemblyData(u32 _address, u32 _size, DataType _type); - virtual ~DisassemblyData() { }; void recheck() override; int getNumLines() override { return (int)lines.size(); }; @@ -179,7 +176,6 @@ class DisassemblyComment: public DisassemblyEntry { public: DisassemblyComment(u32 _address, u32 _size, std::string name, std::string param); - virtual ~DisassemblyComment() { }; void recheck() override { }; int getNumLines() override { return 1; }; diff --git a/Core/Debugger/MemBlockInfo.cpp b/Core/Debugger/MemBlockInfo.cpp index e361b63014..909803b797 100644 --- a/Core/Debugger/MemBlockInfo.cpp +++ b/Core/Debugger/MemBlockInfo.cpp @@ -405,6 +405,29 @@ static inline uint32_t NormalizeAddress(uint32_t addr) { return addr & 0x3FFFFFFF; } +static inline bool MergeRecentMemInfo(const PendingNotifyMem &info, size_t copyLength) { + if (pendingNotifies.size() < 4) + return false; + + for (size_t i = 1; i <= 4; ++i) { + auto &prev = pendingNotifies[pendingNotifies.size() - i]; + if (prev.start >= info.start + info.size || prev.start + prev.size <= info.start) + continue; + + // This means there's overlap, but not a match, so we can't combine any. + if (prev.start != info.start || prev.size > info.size) + return false; + + memcpy(prev.tag, info.tag, copyLength + 1); + prev.size = info.size; + prev.ticks = info.ticks; + prev.pc = info.pc; + return true; + } + + return false; +} + void NotifyMemInfoPC(MemBlockFlags flags, uint32_t start, uint32_t size, uint32_t pc, const char *tagStr, size_t strLength) { if (size == 0) { return; @@ -427,14 +450,17 @@ void NotifyMemInfoPC(MemBlockFlags flags, uint32_t start, uint32_t size, uint32_ info.tag[copyLength] = 0; std::lock_guard guard(pendingMutex); - if (start < 0x08000000) { - pendingNotifyMinAddr1 = std::min(pendingNotifyMinAddr1.load(), start); - pendingNotifyMaxAddr1 = std::max(pendingNotifyMaxAddr1.load(), start + size); - } else { - pendingNotifyMinAddr2 = std::min(pendingNotifyMinAddr2.load(), start); - pendingNotifyMaxAddr2 = std::max(pendingNotifyMaxAddr2.load(), start + size); + // Sometimes we get duplicates, quickly check. + if (!MergeRecentMemInfo(info, copyLength)) { + if (start < 0x08000000) { + pendingNotifyMinAddr1 = std::min(pendingNotifyMinAddr1.load(), start); + pendingNotifyMaxAddr1 = std::max(pendingNotifyMaxAddr1.load(), start + size); + } else { + pendingNotifyMinAddr2 = std::min(pendingNotifyMinAddr2.load(), start); + pendingNotifyMaxAddr2 = std::max(pendingNotifyMaxAddr2.load(), start + size); + } + pendingNotifies.push_back(info); } - pendingNotifies.push_back(info); needFlush = pendingNotifies.size() > MAX_PENDING_NOTIFIES; } diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index 63e087d7a8..93a3d238e2 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -127,9 +127,9 @@ bool SymbolMap::LoadSymbolMap(const Path &filename) { if (!started) continue; - u32 address = -1, size, vaddress = -1; + u32 address = -1, size = 0, vaddress = -1; int moduleIndex = 0; - int typeInt; + int typeInt = ST_NONE; SymbolType type; char name[128] = {0}; @@ -145,7 +145,9 @@ bool SymbolMap::LoadSymbolMap(const Path &filename) { continue; } - sscanf(line, "%08x %08x %x %i %127c", &address, &size, &vaddress, &typeInt, name); + int matched = sscanf(line, "%08x %08x %x %i %127c", &address, &size, &vaddress, &typeInt, name); + if (matched < 1) + continue; type = (SymbolType) typeInt; if (!hasModules) { if (!Memory::IsValidAddress(vaddress)) { diff --git a/Core/Debugger/WebSocket/DisasmSubscriber.cpp b/Core/Debugger/WebSocket/DisasmSubscriber.cpp index 5d766785a2..d467a25cd8 100644 --- a/Core/Debugger/WebSocket/DisasmSubscriber.cpp +++ b/Core/Debugger/WebSocket/DisasmSubscriber.cpp @@ -36,7 +36,7 @@ public: WebSocketDisasmState() { disasm_.setCpu(currentDebugMIPS); } - ~WebSocketDisasmState() override { + ~WebSocketDisasmState() { disasm_.clear(); } diff --git a/Core/Debugger/WebSocket/GPURecordSubscriber.cpp b/Core/Debugger/WebSocket/GPURecordSubscriber.cpp index f31aa26d54..f1aad51e12 100644 --- a/Core/Debugger/WebSocket/GPURecordSubscriber.cpp +++ b/Core/Debugger/WebSocket/GPURecordSubscriber.cpp @@ -23,7 +23,7 @@ #include "GPU/Debugger/Record.h" struct WebSocketGPURecordState : public DebuggerSubscriber { - ~WebSocketGPURecordState() override; + ~WebSocketGPURecordState(); void Dump(DebuggerRequest &req); void Broadcast(net::WebSocketServer *ws) override; diff --git a/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp b/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp index 0d579b6747..1135ad98a2 100644 --- a/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp +++ b/Core/Debugger/WebSocket/GPUStatsSubscriber.cpp @@ -68,7 +68,7 @@ struct DebuggerGPUStatsEvent { struct WebSocketGPUStatsState : public DebuggerSubscriber { WebSocketGPUStatsState(); - ~WebSocketGPUStatsState() override; + ~WebSocketGPUStatsState(); void Get(DebuggerRequest &req); void Feed(DebuggerRequest &req); diff --git a/Core/Debugger/WebSocket/HLESubscriber.cpp b/Core/Debugger/WebSocket/HLESubscriber.cpp index 2a90ca619d..0efe01b222 100644 --- a/Core/Debugger/WebSocket/HLESubscriber.cpp +++ b/Core/Debugger/WebSocket/HLESubscriber.cpp @@ -362,6 +362,42 @@ void WebSocketHLEFuncRemove(DebuggerRequest &req) { json.writeUint("size", funcSize); } +// This function removes function symbols that intersect or lie inside the range +// (Note: this makes no checks whether the range is valid) +// Returns the number of removed functions +static u32 RemoveFuncSymbolsInRange(u32 addr, u32 size) { + u32 func_address = g_symbolMap->GetFunctionStart(addr); + if (func_address == SymbolMap::INVALID_ADDRESS) { + func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); + } + + u32 counter = 0; + while (func_address < addr + size && func_address != SymbolMap::INVALID_ADDRESS) { + g_symbolMap->RemoveFunction(func_address, true); + ++counter; + func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); + } + + if (counter) { + MIPSAnalyst::ForgetFunctions(addr, addr + size - 1); + + // The following was copied from hle.func.remove: + g_symbolMap->SortSymbols(); + + MIPSAnalyst::UpdateHashMap(); + MIPSAnalyst::ApplyHashMap(); + + if (g_Config.bFuncReplacements) { + MIPSAnalyst::ReplaceFunctions(); + } + + // Clear cache for branch lines and such. + DisassemblyManager manager; + manager.clear(); + } + return counter; +} + // Remove function symbols in range (hle.func.removeRange) // // Parameters: @@ -386,34 +422,10 @@ void WebSocketHLEFuncRemoveRange(DebuggerRequest &req) { if (!Memory::IsValidRange(addr, size)) return req.Fail("Address or size outside valid memory"); - u32 first_address = g_symbolMap->GetFunctionStart(addr); - if (first_address == SymbolMap::INVALID_ADDRESS) { - first_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION); - } - - u32 counter = 0; - for (u32 current_addr = first_address; (current_addr < addr + size) && current_addr != SymbolMap::INVALID_ADDRESS; current_addr = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION)) { - g_symbolMap->RemoveFunction(current_addr, true); - ++counter; - } - MIPSAnalyst::ForgetFunctions(addr, addr + size - 1); - - // The following was copied from hle.func.remove: - g_symbolMap->SortSymbols(); - - MIPSAnalyst::UpdateHashMap(); - MIPSAnalyst::ApplyHashMap(); - - if (g_Config.bFuncReplacements) { - MIPSAnalyst::ReplaceFunctions(); - } - - // Clear cache for branch lines and such. - DisassemblyManager manager; - manager.clear(); + u32 count = RemoveFuncSymbolsInRange(addr, size); JsonWriter &json = req.Respond(); - json.writeUint("count", counter); + json.writeUint("count", count); } // Rename a function symbol (hle.func.rename) @@ -465,6 +477,7 @@ void WebSocketHLEFuncRename(DebuggerRequest &req) { // Parameters: // - address: unsigned integer address for the start of the range. // - size: unsigned integer size in bytes for scan. +// - remove: optional bool indicating whether functions that intersect or inside lie inside the range must be removed before scanning // // Response (same event name) with no extra data. void WebSocketHLEFuncScan(DebuggerRequest &req) { @@ -480,9 +493,17 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) { if (!req.ParamU32("size", &size)) return; + bool remove = false; + if (!req.ParamBool("remove", &remove, DebuggerParamType::OPTIONAL)) + return; + if (!Memory::IsValidRange(addr, size)) return req.Fail("Address or size outside valid memory"); + if (remove) { + RemoveFuncSymbolsInRange(addr, size); + } + bool insertSymbols = MIPSAnalyst::ScanForFunctions(addr, addr + size - 1, true); MIPSAnalyst::FinalizeScan(insertSymbols); diff --git a/Core/Debugger/WebSocket/InputSubscriber.cpp b/Core/Debugger/WebSocket/InputSubscriber.cpp index 36278eea0e..fd0f478e76 100644 --- a/Core/Debugger/WebSocket/InputSubscriber.cpp +++ b/Core/Debugger/WebSocket/InputSubscriber.cpp @@ -227,7 +227,7 @@ static bool AnalogValue(DebuggerRequest &req, float *value, const char *name) { } double val = node->value.toNumber(); - if (val < 1.0 || val > 1.0) { + if (val < -1.0 || val > 1.0) { req.Fail(StringFromFormat("Parameter '%s' must be between -1.0 and 1.0", name)); return false; } diff --git a/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp b/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp index 30eb8cdd02..139b9124ec 100644 --- a/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp +++ b/Core/Debugger/WebSocket/MemoryInfoSubscriber.cpp @@ -27,7 +27,7 @@ class WebSocketMemoryInfoState : public DebuggerSubscriber { public: WebSocketMemoryInfoState() { } - ~WebSocketMemoryInfoState() override { + ~WebSocketMemoryInfoState() { UpdateOverride(false); } diff --git a/Core/Debugger/WebSocket/SteppingSubscriber.cpp b/Core/Debugger/WebSocket/SteppingSubscriber.cpp index fcb9296985..b07349a26b 100644 --- a/Core/Debugger/WebSocket/SteppingSubscriber.cpp +++ b/Core/Debugger/WebSocket/SteppingSubscriber.cpp @@ -32,7 +32,7 @@ struct WebSocketSteppingState : public DebuggerSubscriber { WebSocketSteppingState() { disasm_.setCpu(currentDebugMIPS); } - ~WebSocketSteppingState() override { + ~WebSocketSteppingState() { disasm_.clear(); } diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index 3670d15ac8..ffdfcb6f31 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -20,6 +20,8 @@ #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/StringUtils.h" +#include "Core/Config.h" +#include "Core/System.h" #include "Core/CoreTiming.h" #include "Core/Dialog/PSPDialog.h" #include "Core/HLE/sceCtrl.h" @@ -305,3 +307,17 @@ void PSPDialog::DisplayButtons(int flags, const char *caption) PPGeDrawText(text, x1 + 14.5f, 252, textStyle); } } + +int PSPDialog::GetConfirmButton() { + if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) { + return CTRL_CIRCLE; + } + return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; +} + +int PSPDialog::GetCancelButton() { + if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) { + return CTRL_CROSS; + } + return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; +} diff --git a/Core/Dialog/PSPDialog.h b/Core/Dialog/PSPDialog.h index 673bd54f9b..0489a0d2b8 100644 --- a/Core/Dialog/PSPDialog.h +++ b/Core/Dialog/PSPDialog.h @@ -106,6 +106,9 @@ protected: // TODO: Remove this once all dialogs are updated. virtual bool UseAutoStatus() = 0; + static int GetConfirmButton(); + static int GetCancelButton(); + void StartFade(bool fadeIn_); void UpdateFade(int animSpeed); virtual void FinishFadeOut(); diff --git a/Core/Dialog/PSPGamedataInstallDialog.cpp b/Core/Dialog/PSPGamedataInstallDialog.cpp index 30da2953c6..22ef058313 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.cpp +++ b/Core/Dialog/PSPGamedataInstallDialog.cpp @@ -250,7 +250,7 @@ int PSPGamedataInstallDialog::Shutdown(bool force) { return PSPDialog::Shutdown(force); } -std::string PSPGamedataInstallDialog::GetGameDataInstallFileName(SceUtilityGamedataInstallParam *param, std::string filename){ +std::string PSPGamedataInstallDialog::GetGameDataInstallFileName(const SceUtilityGamedataInstallParam *param, std::string filename) { if (!param) return ""; std::string GameDataInstallPath = saveBasePath + param->gameName + param->dataName + "/"; diff --git a/Core/Dialog/PSPGamedataInstallDialog.h b/Core/Dialog/PSPGamedataInstallDialog.h index a74fdb5254..c73db2a01f 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.h +++ b/Core/Dialog/PSPGamedataInstallDialog.h @@ -36,15 +36,15 @@ struct SceUtilityGamedataInstallParam { class PSPGamedataInstallDialog: public PSPDialog { public: PSPGamedataInstallDialog(UtilityDialogType type); - virtual ~PSPGamedataInstallDialog(); + ~PSPGamedataInstallDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; int Abort(); - std::string GetGameDataInstallFileName(SceUtilityGamedataInstallParam *param, std::string filename); + std::string GetGameDataInstallFileName(const SceUtilityGamedataInstallParam *param, std::string filename); protected: // TODO: Manage status correctly. diff --git a/Core/Dialog/PSPMsgDialog.h b/Core/Dialog/PSPMsgDialog.h index 78ee4e54f4..32a4831640 100644 --- a/Core/Dialog/PSPMsgDialog.h +++ b/Core/Dialog/PSPMsgDialog.h @@ -59,18 +59,18 @@ struct pspMessageDialog class PSPMsgDialog: public PSPDialog { public: PSPMsgDialog(UtilityDialogType type); - virtual ~PSPMsgDialog(); + ~PSPMsgDialog(); - virtual int Init(unsigned int paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(unsigned int paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; int Abort(); protected: - virtual bool UseAutoStatus() override { + bool UseAutoStatus() override { return false; } diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 079ff28358..3ea056e8d2 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -261,9 +261,9 @@ int PSPNetconfDialog::Update(int animSpeed) { if (!hideNotice) { const float WRAP_WIDTH = 254.0f; const ImageID confirmBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CROSS") : ImageID("I_CIRCLE"); - const int confirmBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; + const int confirmBtn = GetConfirmButton(); const ImageID cancelBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CIRCLE") : ImageID("I_CROSS"); - const int cancelBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; + const int cancelBtn = GetCancelButton(); PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_CENTER, 0.5f); PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f); diff --git a/Core/Dialog/PSPNetconfDialog.h b/Core/Dialog/PSPNetconfDialog.h index 13d267f5d9..52a3ce203a 100644 --- a/Core/Dialog/PSPNetconfDialog.h +++ b/Core/Dialog/PSPNetconfDialog.h @@ -38,13 +38,13 @@ struct SceUtilityNetconfParam { class PSPNetconfDialog: public PSPDialog { public: PSPNetconfDialog(UtilityDialogType type); - virtual ~PSPNetconfDialog(); + ~PSPNetconfDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon* GetCommonParam() override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon* GetCommonParam() override; protected: bool UseAutoStatus() override { diff --git a/Core/Dialog/PSPNpSigninDialog.h b/Core/Dialog/PSPNpSigninDialog.h index 15aac7b0c9..2b31922735 100644 --- a/Core/Dialog/PSPNpSigninDialog.h +++ b/Core/Dialog/PSPNpSigninDialog.h @@ -34,13 +34,13 @@ struct SceUtilityNpSigninParam { class PSPNpSigninDialog: public PSPDialog { public: PSPNpSigninDialog(UtilityDialogType type); - virtual ~PSPNpSigninDialog(); + ~PSPNpSigninDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon* GetCommonParam() override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon* GetCommonParam() override; protected: bool UseAutoStatus() override { diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 8eb37918ce..54f2ea723d 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -346,7 +346,7 @@ int PSPOskDialog::Init(u32 oskPtr) { inputChars += c; } - languageMapping = GetLangValuesMapping(); + languageMapping = g_Config.GetLangValuesMapping(); // Eat any keys pressed before the dialog inited. UpdateButtons(); @@ -941,8 +941,9 @@ int PSPOskDialog::Update(int animSpeed) { return SCE_ERROR_UTILITY_INVALID_STATUS; } - int cancelButton = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS; - int confirmButton = cancelButton == CTRL_CROSS ? CTRL_CIRCLE : CTRL_CROSS; + int cancelButton = GetCancelButton(); + int confirmButton = GetConfirmButton(); + static int cancelBtnFramesHeld = 0; static int confirmBtnFramesHeld = 0; static int leftBtnFramesHeld = 0; @@ -979,7 +980,7 @@ int PSPOskDialog::Update(int animSpeed) { PPGeDrawImage(ImageID("I_SQUARE"), 365, 222, 16, 16, guideStyle); PPGeDrawText(di->T("Space"), 390, 222, actionStyle); - if (g_Config.iButtonPreference != PSP_SYSTEMPARAM_BUTTON_CIRCLE) { + if (GetConfirmButton() != PSP_SYSTEMPARAM_BUTTON_CIRCLE) { PPGeDrawImage(ImageID("I_CROSS"), 45, 222, 16, 16, guideStyle); PPGeDrawImage(ImageID("I_CIRCLE"), 45, 247, 16, 16, guideStyle); } else { diff --git a/Core/Dialog/PSPOskDialog.h b/Core/Dialog/PSPOskDialog.h index c760afb1e4..b4aeefc745 100644 --- a/Core/Dialog/PSPOskDialog.h +++ b/Core/Dialog/PSPOskDialog.h @@ -213,16 +213,16 @@ enum class PSPOskNativeStatus { class PSPOskDialog: public PSPDialog { public: PSPOskDialog(UtilityDialogType type); - virtual ~PSPOskDialog(); + ~PSPOskDialog(); - virtual int Init(u32 oskPtr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(u32 oskPtr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; protected: - virtual bool UseAutoStatus() override { + bool UseAutoStatus() override { return false; } diff --git a/Core/Dialog/PSPPlaceholderDialog.h b/Core/Dialog/PSPPlaceholderDialog.h index 4c81efe636..b494d92944 100644 --- a/Core/Dialog/PSPPlaceholderDialog.h +++ b/Core/Dialog/PSPPlaceholderDialog.h @@ -22,9 +22,9 @@ class PSPPlaceholderDialog: public PSPDialog { public: PSPPlaceholderDialog(UtilityDialogType type); - virtual ~PSPPlaceholderDialog(); + ~PSPPlaceholderDialog(); - virtual int Init(); - virtual int Update(int animSpeed) override; + int Init(); + int Update(int animSpeed) override; }; diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 91994d3f36..8e0bfcb1ba 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -70,6 +70,8 @@ static bool IsNotVisibleAction(SceUtilitySavedataType type) { case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_READDATA: + case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASE: case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: return true; @@ -155,7 +157,7 @@ int PSPSaveDialog::Init(int paramAddr) break; } - if(!param.wouldHasMultiSaveName(param.GetPspParam())) + if (!param.WouldHaveMultiSaveName(param.GetPspParam())) currentSelectedSave = 0; switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode) @@ -222,6 +224,8 @@ int PSPSaveDialog::Init(int paramAddr) case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_READDATA: + case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE: + case SCE_UTILITY_SAVEDATA_TYPE_ERASE: case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: display = DS_NONE; break; @@ -1251,7 +1255,7 @@ void PSPSaveDialog::DoState(PointerWrap &p) { // Just reset it. bool hasParam = param.GetPspParam() != NULL; Do(p, hasParam); - if (hasParam) { + if (hasParam && p.mode == p.MODE_READ) { param.SetPspParam(&request); } Do(p, requestAddr); diff --git a/Core/Dialog/PSPSaveDialog.h b/Core/Dialog/PSPSaveDialog.h index 90f8d6312a..be6024ac52 100644 --- a/Core/Dialog/PSPSaveDialog.h +++ b/Core/Dialog/PSPSaveDialog.h @@ -72,18 +72,18 @@ class PSPSaveDialog: public PSPDialog { public: PSPSaveDialog(UtilityDialogType type); - virtual ~PSPSaveDialog(); + ~PSPSaveDialog(); - virtual int Init(int paramAddr); - virtual int Update(int animSpeed) override; - virtual int Shutdown(bool force = false) override; - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(int paramAddr); + int Update(int animSpeed) override; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; void ExecuteIOAction(); protected: - virtual bool UseAutoStatus() override { + bool UseAutoStatus() override { return false; } diff --git a/Core/Dialog/PSPScreenshotDialog.h b/Core/Dialog/PSPScreenshotDialog.h index ae83e9e8ca..760cd8fcc7 100644 --- a/Core/Dialog/PSPScreenshotDialog.h +++ b/Core/Dialog/PSPScreenshotDialog.h @@ -25,13 +25,13 @@ struct SceUtilityScreenshotParams; class PSPScreenshotDialog : public PSPDialog { public: PSPScreenshotDialog(UtilityDialogType type); - virtual ~PSPScreenshotDialog(); + ~PSPScreenshotDialog(); - virtual int Init(u32 paramAddr); - virtual int Update(int animSpeed) override; - virtual int ContStart(); - virtual void DoState(PointerWrap &p) override; - virtual pspUtilityDialogCommon *GetCommonParam() override; + int Init(u32 paramAddr); + int Update(int animSpeed) override; + int ContStart(); + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; protected: // TODO: Manage status correctly. diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 53d6d819a3..b78f728788 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include #include "Common/Log.h" #include "Common/Data/Text/I18n.h" #include "Common/Data/Format/ZIMLoad.h" @@ -36,14 +38,15 @@ #include "Core/HW/MemoryStick.h" #include "Core/Util/PPGeDraw.h" -#include - static const std::string ICON0_FILENAME = "ICON0.PNG"; static const std::string ICON1_FILENAME = "ICON1.PMF"; static const std::string PIC1_FILENAME = "PIC1.PNG"; static const std::string SND0_FILENAME = "SND0.AT3"; static const std::string SFO_FILENAME = "PARAM.SFO"; +static const int FILE_LIST_COUNT_MAX = 99; +static const u32 FILE_LIST_TOTAL_SIZE = sizeof(SaveSFOFileListEntry) * FILE_LIST_COUNT_MAX; + static const std::string savePath = "ms0:/PSP/SAVEDATA/"; namespace @@ -83,7 +86,7 @@ namespace return result != 0; } - bool WritePSPFile(std::string filename, u8 *data, SceSize dataSize) + bool WritePSPFile(std::string filename, const u8 *data, SceSize dataSize) { int handle = pspFileSystem.OpenFile(filename, (FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE | FILEACCESS_TRUNCATE)); if (handle < 0) @@ -382,6 +385,39 @@ int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { ClearCaches(); pspFileSystem.RemoveFile(filePath); + // Update PARAM.SFO to remove the file, if it was in the list. + std::shared_ptr sfoFile = LoadCachedSFO(sfoPath); + if (sfoFile) { + // Note: do not update values such as TITLE in this operation. + u32 fileListSize = 0; + SaveSFOFileListEntry *fileList = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &fileListSize); + size_t fileListCount = fileListSize / sizeof(SaveSFOFileListEntry); + bool changed = false; + for (size_t i = 0; i < fileListCount; ++i) { + if (strncmp(fileList[i].filename, fileName.c_str(), sizeof(fileList[i].filename)) != 0) + continue; + + memset(fileList[i].filename, 0, sizeof(fileList[i].filename)); + memset(fileList[i].hash, 0, sizeof(fileList[i].hash)); + changed = true; + break; + } + + if (changed) { + std::unique_ptr updatedList(new u8[fileListSize]); + memcpy(updatedList.get(), fileList, fileListSize); + sfoFile->SetValue("SAVEDATA_FILE_LIST", updatedList.get(), fileListSize, (int)FILE_LIST_TOTAL_SIZE); + + u8 *sfoData; + size_t sfoSize; + sfoFile->WriteSFO(&sfoData, &sfoSize); + + ClearCaches(); + WritePSPFile(sfoPath, sfoData, (SceSize)sfoSize); + delete[] sfoData; + } + } + return 0; } @@ -470,8 +506,6 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD // Always write and update the file list. // For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding - const int FILE_LIST_COUNT_MAX = 99; - const u32 FILE_LIST_TOTAL_SIZE = sizeof(SaveSFOFileListEntry) * FILE_LIST_COUNT_MAX; u32 tmpDataSize = 0; SaveSFOFileListEntry *tmpDataOrig = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); SaveSFOFileListEntry *updatedList = new SaveSFOFileListEntry[FILE_LIST_COUNT_MAX]; @@ -825,7 +859,6 @@ std::vector SavedataParam::GetSFOEntries(const std::string return result; } - const int FILE_LIST_COUNT_MAX = 99; u32 sfoFileListSize = 0; SaveSFOFileListEntry *sfoFileList = (SaveSFOFileListEntry *)sfoFile->GetValueData("SAVEDATA_FILE_LIST", &sfoFileListSize); const u32 count = std::min((u32)FILE_LIST_COUNT_MAX, sfoFileListSize / (u32)sizeof(SaveSFOFileListEntry)); @@ -1483,7 +1516,7 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) saveDataListCount++; } - if (saveDataListCount > 0 && wouldHasMultiSaveName(param)) { + if (saveDataListCount > 0 && WouldHaveMultiSaveName(param)) { hasMultipleFileName = true; saveDataList = new SaveFileInfo[saveDataListCount]; @@ -1809,8 +1842,7 @@ int SavedataParam::GetLastEmptySave() return idx; } -int SavedataParam::GetSaveNameIndex(SceUtilitySavedataParam* param) -{ +int SavedataParam::GetSaveNameIndex(const SceUtilitySavedataParam *param) { std::string saveName = GetSaveName(param); for (int i = 0; i < saveNameListDataCount; i++) { @@ -1824,7 +1856,7 @@ int SavedataParam::GetSaveNameIndex(SceUtilitySavedataParam* param) return 0; } -bool SavedataParam::wouldHasMultiSaveName(SceUtilitySavedataParam* param) { +bool SavedataParam::WouldHaveMultiSaveName(const SceUtilitySavedataParam *param) { switch ((SceUtilitySavedataType)(u32)param->mode) { case SCE_UTILITY_SAVEDATA_TYPE_LOAD: case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: @@ -1857,13 +1889,13 @@ void SavedataParam::DoState(PointerWrap &p) { Do(p, saveDataListCount); Do(p, saveNameListDataCount); if (p.mode == p.MODE_READ) { - if (saveDataList != NULL) + if (saveDataList) delete [] saveDataList; if (saveDataListCount != 0) { saveDataList = new SaveFileInfo[saveDataListCount]; DoArray(p, saveDataList, saveDataListCount); } else { - saveDataList = NULL; + saveDataList = nullptr; } } else @@ -1904,7 +1936,7 @@ std::shared_ptr SavedataParam::LoadCachedSFO(const std::string &pa return sfoCache_.at(path); } -int SavedataParam::GetSaveCryptMode(SceUtilitySavedataParam *param, const std::string &saveDirName) { +int SavedataParam::GetSaveCryptMode(const SceUtilitySavedataParam *param, const std::string &saveDirName) { std::string dirPath = GetSaveFilePath(param, GetSaveDir(param, saveDirName)); std::string sfopath = dirPath + "/" + SFO_FILENAME; std::shared_ptr sfoFile = LoadCachedSFO(sfopath); diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 65a1ac5cd1..257fc02746 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -317,7 +317,7 @@ public: bool GetList(SceUtilitySavedataParam* param); int GetFilesList(SceUtilitySavedataParam* param, u32 requestAddr); bool GetSize(SceUtilitySavedataParam* param); - int GetSaveCryptMode(SceUtilitySavedataParam* param, const std::string &saveDirName); + int GetSaveCryptMode(const SceUtilitySavedataParam *param, const std::string &saveDirName); bool IsInSaveDataList(std::string saveName, int count); std::string GetGameName(const SceUtilitySavedataParam *param) const; @@ -351,9 +351,9 @@ public: int GetLastDataSave(); int GetFirstEmptySave(); int GetLastEmptySave(); - int GetSaveNameIndex(SceUtilitySavedataParam* param); + int GetSaveNameIndex(const SceUtilitySavedataParam *param); - bool wouldHasMultiSaveName(SceUtilitySavedataParam* param); + bool WouldHaveMultiSaveName(const SceUtilitySavedataParam *param); void ClearCaches(); diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index a4a6bfb856..2baf2690d6 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -128,7 +128,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { if (log) { DEBUG_LOG(LOADER, "rel at: %08x info: %08x type: %i", addr, info, type); } - u32 relocateTo = segmentVAddr[relative]; + u32 relocateTo = relative >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[relative]; switch (type) { case R_MIPS_32: @@ -289,9 +289,9 @@ void ElfReader::LoadRelocations2(int rel_seg) } }else{ addr_seg = seg; - relocate_to = segmentVAddr[addr_seg]; + relocate_to = addr_seg >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[addr_seg]; if (!Memory::IsValidAddress(relocate_to)) { - ERROR_LOG(LOADER, "ELF: Bad address to relocate to: %08x", relocate_to); + ERROR_LOG(LOADER, "ELF: Bad address to relocate to: %08x (segment %d)", relocate_to, addr_seg); continue; } diff --git a/Core/FileLoaders/CachingFileLoader.h b/Core/FileLoaders/CachingFileLoader.h index e778265cce..a4299b567d 100644 --- a/Core/FileLoaders/CachingFileLoader.h +++ b/Core/FileLoaders/CachingFileLoader.h @@ -27,7 +27,7 @@ class CachingFileLoader : public ProxiedFileLoader { public: CachingFileLoader(FileLoader *backend); - ~CachingFileLoader() override; + ~CachingFileLoader(); bool Exists() override; bool ExistsFast() override; diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index dd8d59bf05..20c3ae0ad5 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -480,7 +480,7 @@ bool DiskCachingFileLoaderCache::ReadBlockData(u8 *dest, BlockInfo &info, size_t return !failed; } -void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, u8 *src) { +void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, const u8 *src) { if (!f_) { return; } diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index bfbf780c2b..242c28ab5d 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -31,7 +31,7 @@ class DiskCachingFileLoaderCache; class DiskCachingFileLoader : public ProxiedFileLoader { public: DiskCachingFileLoader(FileLoader *backend); - ~DiskCachingFileLoader() override; + ~DiskCachingFileLoader(); bool Exists() override; bool ExistsFast() override; @@ -95,7 +95,7 @@ private: struct BlockInfo; bool ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size); - void WriteBlockData(BlockInfo &info, u8 *src); + void WriteBlockData(BlockInfo &info, const u8 *src); void WriteIndexData(u32 indexPos, BlockInfo &info); s64 GetBlockOffset(u32 block); diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index 84a4361097..ec92b8b9d5 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -30,21 +30,21 @@ class HTTPFileLoader : public FileLoader { public: HTTPFileLoader(const ::Path &filename); - virtual ~HTTPFileLoader() override; + ~HTTPFileLoader(); bool IsRemote() override { return true; } - virtual bool Exists() override; - virtual bool ExistsFast() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual Path GetPath() const override; + bool Exists() override; + bool ExistsFast() override; + bool IsDirectory() override; + s64 FileSize() override; + Path GetPath() const override; - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; void Cancel() override { cancel_ = true; diff --git a/Core/FileLoaders/LocalFileLoader.h b/Core/FileLoaders/LocalFileLoader.h index 9e1f37c10f..8db0b24b02 100644 --- a/Core/FileLoaders/LocalFileLoader.h +++ b/Core/FileLoaders/LocalFileLoader.h @@ -30,15 +30,15 @@ typedef void *HANDLE; class LocalFileLoader : public FileLoader { public: LocalFileLoader(const Path &filename); - virtual ~LocalFileLoader(); + ~LocalFileLoader(); - virtual bool Exists() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual Path GetPath() const override { + bool Exists() override; + bool IsDirectory() override; + s64 FileSize() override; + Path GetPath() const override { return filename_; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; private: #ifndef _WIN32 diff --git a/Core/FileLoaders/RamCachingFileLoader.h b/Core/FileLoaders/RamCachingFileLoader.h index 44c375d442..dde5e74ecb 100644 --- a/Core/FileLoaders/RamCachingFileLoader.h +++ b/Core/FileLoaders/RamCachingFileLoader.h @@ -27,7 +27,7 @@ class RamCachingFileLoader : public ProxiedFileLoader { public: RamCachingFileLoader(FileLoader *backend); - ~RamCachingFileLoader() override; + ~RamCachingFileLoader(); bool Exists() override; bool ExistsFast() override; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index af8ea370a4..27abc90564 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -115,6 +115,11 @@ Path DirectoryFileSystem::GetLocalPath(std::string internalPath) const { bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, FileAccess access, u32 &error) { error = 0; + if (access == FILEACCESS_NONE) { + error = SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; + return false; + } + #if HOST_IS_CASE_SENSITIVE if (access & (FILEACCESS_APPEND | FILEACCESS_CREATE | FILEACCESS_WRITE)) { DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str()); @@ -707,7 +712,7 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { #ifdef _WIN32 #define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL -static void tmFromFiletime(tm &dest, FILETIME &src) { +static void tmFromFiletime(tm &dest, const FILETIME &src) { u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL; u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US; diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 350b97cd8f..d2eeca6651 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -77,7 +77,7 @@ public: class SequentialHandleAllocator : public IHandleAllocator { public: SequentialHandleAllocator() : handle_(1) {} - virtual u32 GetNewHandle() override { + u32 GetNewHandle() override { u32 res = handle_++; if (handle_ < 0) { // Some code assumes it'll never become 0. @@ -85,7 +85,7 @@ public: } return res; } - virtual void FreeHandle(u32 handle) override {} + void FreeHandle(u32 handle) override {} private: int handle_; }; @@ -142,7 +142,7 @@ public: class EmptyFileSystem : public IFileSystem { public: - virtual void DoState(PointerWrap &p) override {} + void DoState(PointerWrap &p) override {} std::vector GetDirListing(const std::string &path, bool *exists = nullptr) override { if (exists) *exists = false; @@ -158,14 +158,14 @@ public: size_t SeekFile(u32 handle, s32 position, FileMove type) override {return 0;} PSPFileInfo GetFileInfo(std::string filename) override {PSPFileInfo f; return f;} bool OwnsHandle(u32 handle) override {return false;} - virtual bool MkDir(const std::string &dirname) override {return false;} - virtual bool RmDir(const std::string &dirname) override {return false;} - virtual int RenameFile(const std::string &from, const std::string &to) override {return -1;} - virtual bool RemoveFile(const std::string &filename) override {return false;} - virtual int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override {return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } - virtual PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } - virtual FileSystemFlags Flags() override { return FileSystemFlags::NONE; } - virtual u64 FreeSpace(const std::string &path) override { return 0; } + bool MkDir(const std::string &dirname) override {return false;} + bool RmDir(const std::string &dirname) override {return false;} + int RenameFile(const std::string &from, const std::string &to) override {return -1;} + bool RemoveFile(const std::string &filename) override {return false;} + int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override { return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } + PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } + FileSystemFlags Flags() override { return FileSystemFlags::NONE; } + u64 FreeSpace(const std::string &path) override { return 0; } bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } }; diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 545f21bddc..e574423dd6 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -91,7 +91,7 @@ public: int MapFilePath(const std::string &inpath, std::string &outpath, MountPoint **system); inline int MapFilePath(const std::string &_inpath, std::string &outpath, IFileSystem **system) { - MountPoint *mountPoint; + MountPoint *mountPoint = nullptr; int error = MapFilePath(_inpath, outpath, &mountPoint); if (error == 0) { *system = mountPoint->system.get(); diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index dbe130f30c..5c5a6714e2 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -651,7 +651,7 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { #ifdef _WIN32 #define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL -static void tmFromFiletime(tm &dest, FILETIME &src) +static void tmFromFiletime(tm &dest, const FILETIME &src) { u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL; u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US; diff --git a/Core/HLE/HLEHelperThread.cpp b/Core/HLE/HLEHelperThread.cpp index 0975d1ea96..60f7efb759 100644 --- a/Core/HLE/HLEHelperThread.cpp +++ b/Core/HLE/HLEHelperThread.cpp @@ -26,7 +26,7 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPSCodeUtils.h" -HLEHelperThread::HLEHelperThread() : id_(-1), entry_(0) { +HLEHelperThread::HLEHelperThread() : id_(0), entry_(0) { } HLEHelperThread::HLEHelperThread(const char *threadName, const u32 instructions[], u32 instrCount, u32 prio, int stacksize) { @@ -52,7 +52,7 @@ HLEHelperThread::HLEHelperThread(const char *threadName, const char *module, con } HLEHelperThread::~HLEHelperThread() { - if (id_) + if (id_ > 0) __KernelDeleteThread(id_, SCE_KERNEL_ERROR_THREAD_TERMINATED, "helper deleted"); if (entry_) kernelMemory.Free(entry_); diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index cb775c7ebf..016a19e5c1 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -305,6 +305,7 @@ void RegisterAllModules() { Register_sceOpenPSID_driver(); Register_semaphore(); Register_sceDdrdb(); + Register_mp4msv(); // add new modules here. } diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 5e8c093671..65461ff902 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -233,8 +233,9 @@ static int Replace_memcpy16() { bool skip = false; // Some games use memcpy on executable code. We need to flush emuhack ops. - currentMIPS->InvalidateICache(srcPtr, bytes); - if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMCPY) == 0) { + if (bytes != 0) + currentMIPS->InvalidateICache(srcPtr, bytes); + if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMCPY) == 0 && bytes != 0) { if (Memory::IsVRAMAddress(destPtr) || Memory::IsVRAMAddress(srcPtr)) { skip = gpu->PerformMemoryCopy(destPtr, srcPtr, bytes); } @@ -305,7 +306,7 @@ static int Replace_memmove() { bool skip = false; // Some games use memcpy on executable code. We need to flush emuhack ops. - if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMMOVE) == 0) { + if ((skipGPUReplacements & (int)GPUReplacementSkip::MEMMOVE) == 0 && bytes != 0) { currentMIPS->InvalidateICache(srcPtr, bytes); if (Memory::IsVRAMAddress(destPtr) || Memory::IsVRAMAddress(srcPtr)) { skip = gpu->PerformMemoryCopy(destPtr, srcPtr, bytes); @@ -1270,10 +1271,12 @@ static u32 marvelalliance1_copy_size = 0; static int Hook_marvelalliance1_copy_a1_before() { marvelalliance1_copy_src = currentMIPS->r[MIPS_REG_A1]; marvelalliance1_copy_dst = currentMIPS->r[MIPS_REG_V1]; - marvelalliance1_copy_size = currentMIPS->r[MIPS_REG_V0] - currentMIPS->r[MIPS_REG_V1]; + marvelalliance1_copy_size = currentMIPS->r[MIPS_REG_V0] - currentMIPS->r[MIPS_REG_A1]; - gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); - NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a1_before"); + if (Memory::IsValidRange(marvelalliance1_copy_src, marvelalliance1_copy_size)) { + gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); + NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a1_before"); + } return 0; } @@ -1283,15 +1286,19 @@ static int Hook_marvelalliance1_copy_a2_before() { marvelalliance1_copy_dst = currentMIPS->r[MIPS_REG_V0]; marvelalliance1_copy_size = currentMIPS->r[MIPS_REG_A1] - currentMIPS->r[MIPS_REG_A2]; - gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); - NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a2_before"); + if (Memory::IsValidRange(marvelalliance1_copy_src, marvelalliance1_copy_size)) { + gpu->PerformReadbackToMemory(marvelalliance1_copy_src, marvelalliance1_copy_size); + NotifyMemInfo(MemBlockFlags::WRITE, marvelalliance1_copy_src, marvelalliance1_copy_size, "marvelalliance1_copy_a2_before"); + } return 0; } static int Hook_marvelalliance1_copy_after() { - gpu->PerformWriteColorFromMemory(marvelalliance1_copy_dst, marvelalliance1_copy_size); - NotifyMemInfo(MemBlockFlags::READ, marvelalliance1_copy_dst, marvelalliance1_copy_size, "marvelalliance1_copy_after"); + if (Memory::IsValidRange(marvelalliance1_copy_dst, marvelalliance1_copy_size)) { + gpu->PerformWriteColorFromMemory(marvelalliance1_copy_dst, marvelalliance1_copy_size); + NotifyMemInfo(MemBlockFlags::READ, marvelalliance1_copy_dst, marvelalliance1_copy_size, "marvelalliance1_copy_after"); + } return 0; } @@ -1651,7 +1658,8 @@ std::map SaveAndClearReplacements() { std::map saved; for (auto it = replacedInstructions.begin(), end = replacedInstructions.end(); it != end; ++it) { const u32 addr = it->first; - const u32 curInstr = Memory::Read_U32(addr); + // This will not retain jit blocks. + const u32 curInstr = Memory::Read_Opcode_JIT(addr).encoding; if (MIPS_IS_REPLACEMENT(curInstr)) { saved[addr] = curInstr; Memory::Write_U32(it->second, addr); diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index dfcc535df0..2a18f05534 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -180,7 +180,7 @@ std::string ip2str(in_addr in, bool maskPublicIP) { return std::string(str); } -std::string mac2str(SceNetEtherAddr* mac) { +std::string mac2str(const SceNetEtherAddr *mac) { char str[18] = ":::::"; if (mac != NULL) { diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index b3594e5a7b..c448d0189b 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -1017,7 +1017,7 @@ bool isPTPPortInUse(uint16_t port, bool forListen, SceNetEtherAddr* dstmac = nul std::string ip2str(in_addr in, bool maskPublicIP = true); // Convert MAC address to string -std::string mac2str(SceNetEtherAddr* mac); +std::string mac2str(const SceNetEtherAddr *mac); /* * Matching Members diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index d0577d46f2..342d522627 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -544,7 +544,7 @@ void __DisplayFlip(int cyclesLate) { // non-buffered rendering. The interaction with frame skipping seems to need // some work. // But, let's flip at least once every 10 vblanks, to update fps, etc. - const bool noRecentFlip = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && numVBlanksSinceFlip >= 10; + const bool noRecentFlip = !g_Config.bSkipBufferEffects && numVBlanksSinceFlip >= 10; // Also let's always flip for animated shaders. bool postEffectRequiresFlip = false; @@ -556,7 +556,7 @@ void __DisplayFlip(int cyclesLate) { fastForwardSkipFlip = true; } - if (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) { + if (!g_Config.bSkipBufferEffects) { postEffectRequiresFlip = duplicateFrames || g_Config.bShaderChainRequires60FPS; } @@ -777,7 +777,7 @@ void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelFormat, int sync) // IMMEDIATE means that the buffer is fine. We can just flip immediately. // Doing it in non-buffered though creates problems (black screen) on occasion though // so let's not. - if (!flippedThisFrame && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) { + if (!flippedThisFrame && !g_Config.bSkipBufferEffects) { double before_flip = time_now_d(); __DisplayFlip(0); double after_flip = time_now_d(); diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index 5fba8f9b94..3735eb2a84 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -49,7 +49,7 @@ static int __DmacMemcpy(u32 dst, u32 src, u32 size) { if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) { skip = gpu->PerformMemoryCopy(dst, src, size); } - if (!skip) { + if (!skip && size != 0) { currentMIPS->InvalidateICache(src, size); if (MemBlockInfoDetailed(size)) { const std::string tag = GetMemWriteTagAt("DmacMemcpy/", src, size); diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index 086cc83c17..6bebff1fde 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -24,6 +24,7 @@ #include "Core/MIPS/MIPS.h" #include "Core/Config.h" #include "Core/MemMap.h" +#include "Core/System.h" const int PSP_UMD_POPUP_DISABLE = 0; const int PSP_UMD_POPUP_ENABLE = 1; @@ -40,7 +41,12 @@ static u32 backlightOffTime; void __ImposeInit() { language = g_Config.iLanguage; - buttonValue = g_Config.iButtonPreference; + if (PSP_CoreParameter().compat.flags().EnglishOrJapaneseOnly) { + if (language != PSP_SYSTEMPARAM_LANGUAGE_ENGLISH && language != PSP_SYSTEMPARAM_LANGUAGE_JAPANESE) { + language = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + } + } + buttonValue = PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm ? PSP_SYSTEMPARAM_BUTTON_CIRCLE : g_Config.iButtonPreference; umdPopup = PSP_UMD_POPUP_DISABLE; backlightOffTime = 0; } diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index f4c98dfb6b..d2cf9ec311 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -70,6 +70,8 @@ extern "C" { // For headless screenshots. #include "Core/HLE/sceDisplay.h" +// For EMULATOR_DEVCTL__GET_SCALE +#include static const int ERROR_ERRNO_IO_ERROR = 0x80010005; static const int ERROR_MEMSTICK_DEVCTL_BAD_PARAMS = 0x80220081; @@ -269,8 +271,9 @@ public: if (p.mode == p.MODE_READ) { pgdInfo = (PGD_DESC*) malloc(sizeof(PGD_DESC)); } - p.DoVoid(pgdInfo, sizeof(PGD_DESC)); - if (p.mode == p.MODE_READ) { + if (pgdInfo) + p.DoVoid(pgdInfo, sizeof(PGD_DESC)); + if (p.mode == p.MODE_READ && pgdInfo) { pgdInfo->block_buf = (u8 *)malloc(pgdInfo->block_size * 2); } } @@ -794,7 +797,7 @@ void __IoShutdown() { memStickFatCallbacks.clear(); } -static std::string IODetermineFilename(FileNode *f) { +static std::string IODetermineFilename(const FileNode *f) { uint64_t offset = pspFileSystem.GetSeekPos(f->handle); if ((pspFileSystem.DevType(f->handle) & PSPDevType::BLOCK) != 0) { return StringFromFormat("%s offset 0x%08llx", f->fullpath.c_str(), offset * 2048); @@ -1980,12 +1983,29 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o if (!strcmp(name, "kemulator:") || !strcmp(name, "emulator:")) { // Emulator special tricks! + + enum + { + EMULATOR_DEVCTL__GET_HAS_DISPLAY = 1, + EMULATOR_DEVCTL__SEND_OUTPUT, + EMULATOR_DEVCTL__IS_EMULATOR, + EMULATOR_DEVCTL__VERIFY_STATE, + + EMULATOR_DEVCTL__EMIT_SCREENSHOT = 0x20, + + EMULATOR_DEVCTL__TOGGLE_FASTFORWARD = 0x30, + EMULATOR_DEVCTL__GET_ASPECT_RATIO, + EMULATOR_DEVCTL__GET_SCALE, + EMULATOR_DEVCTL__GET_LTRIGGER, + EMULATOR_DEVCTL__GET_RTRIGGER + }; + switch (cmd) { - case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY + case EMULATOR_DEVCTL__GET_HAS_DISPLAY: if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(PSP_CoreParameter().headLess ? 0 : 1, outPtr); return 0; - case 2: // EMULATOR_DEVCTL__SEND_OUTPUT + case EMULATOR_DEVCTL__SEND_OUTPUT: { std::string data(Memory::GetCharPointer(argAddr), argLen); if (PSP_CoreParameter().printfEmuLog) { @@ -1999,17 +2019,17 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o } return 0; } - case 3: // EMULATOR_DEVCTL__IS_EMULATOR + case EMULATOR_DEVCTL__IS_EMULATOR: if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(1, outPtr); return 0; - case 4: // EMULATOR_DEVCTL__VERIFY_STATE + case EMULATOR_DEVCTL__VERIFY_STATE: // Note that this is async, and makes sure the save state matches up. SaveState::Verify(); // TODO: Maybe save/load to a file just to be sure? return 0; - case 0x20: // EMULATOR_DEVCTL__EMIT_SCREENSHOT + case EMULATOR_DEVCTL__EMIT_SCREENSHOT: { PSPPointer topaddr; u32 linesize; @@ -2019,6 +2039,39 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o host->SendDebugScreenshot(topaddr, linesize, 272); return 0; } + case EMULATOR_DEVCTL__TOGGLE_FASTFORWARD: + if (argAddr) + PSP_CoreParameter().fastForward = true; + else + PSP_CoreParameter().fastForward = false; + return 0; + case EMULATOR_DEVCTL__GET_ASPECT_RATIO: + if (Memory::IsValidAddress(outPtr)) { + // TODO: Share code with CenterDisplayOutputRect to take a few more things into account. + // I have a planned further refactoring. + float ar; + if (g_Config.bDisplayStretch) { + ar = (float)dp_xres / (float)dp_yres; + } else { + ar = g_Config.fDisplayAspectRatio * (480.0f / 272.0f); + } + Memory::Write_Float(ar, outPtr); + } + return 0; + case EMULATOR_DEVCTL__GET_SCALE: + if (Memory::IsValidAddress(outPtr)) { + // TODO: Maybe do something more sophisticated taking the longest side and screen rotation + // into account, etc. + float scale = float(dp_xres) * g_Config.fDisplayScale / 480.0f; + Memory::Write_Float(scale, outPtr); + } + return 0; + case EMULATOR_DEVCTL__GET_LTRIGGER: + //To-do + return 0; + case EMULATOR_DEVCTL__GET_RTRIGGER: + //To-do + return 0; } ERROR_LOG(SCEIO, "sceIoDevCtl: UNKNOWN PARAMETERS"); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index b9d1028b48..a7f5b7cb82 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -392,7 +392,8 @@ int sceKernelDcacheInvalidateRange(u32 addr, int size) int sceKernelIcacheInvalidateRange(u32 addr, int size) { DEBUG_LOG(CPU, "sceKernelIcacheInvalidateRange(%08x, %i)", addr, size); - currentMIPS->InvalidateICache(addr, size); + if (size != 0) + currentMIPS->InvalidateICache(addr, size); return 0; } @@ -712,7 +713,7 @@ const HLEFunction ThreadManForUser[] = {0XA66B0120, &WrapU_IU, "sceKernelReferEventFlagStatus", 'x', "ix" }, {0X8FFDF9A2, &WrapI_IIU, "sceKernelCancelSema", 'i', "iix" }, - {0XD6DA4BA1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiix" }, + {0XD6DA4BA1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiip" }, {0X28B6489C, &WrapI_I, "sceKernelDeleteSema", 'i', "i" }, {0X58B1F937, &WrapI_II, "sceKernelPollSema", 'i', "ii" }, {0XBC6FEBC5, &WrapI_IU, "sceKernelReferSemaStatus", 'i', "ip" }, @@ -734,7 +735,7 @@ const HLEFunction ThreadManForUser[] = {0XB011B11F, &WrapI_IIU, "sceKernelLockMutex", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, {0X5BF4DD27, &WrapI_IIU, "sceKernelLockMutexCB", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED }, {0X6B30100F, &WrapI_II, "sceKernelUnlockMutex", 'i', "ii" }, - {0XB7D098C6, &WrapI_CUIU, "sceKernelCreateMutex", 'i', "sxix" }, + {0XB7D098C6, &WrapI_CUIU, "sceKernelCreateMutex", 'i', "sxip" }, {0X0DDCD2C9, &WrapI_II, "sceKernelTryLockMutex", 'i', "ii" }, {0XA9C2CB9A, &WrapI_IU, "sceKernelReferMutexStatus", 'i', "ip" }, {0X87D9223C, &WrapI_IIU, "sceKernelCancelMutex", 'i', "iix" }, @@ -898,7 +899,7 @@ const HLEFunction ThreadManForKernel[] = {0X75156E8F, &WrapI_I, "sceKernelResumeThread", 'i', "i", HLE_KERNEL_SYSCALL }, {0X94416130, &WrapU_UUUU, "sceKernelGetThreadmanIdList", 'x', "xxxx", HLE_KERNEL_SYSCALL }, {0x278c0df5, &WrapI_IU, "sceKernelWaitThreadEnd", 'i', "ix", HLE_KERNEL_SYSCALL }, - {0xd6da4ba1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiix", HLE_KERNEL_SYSCALL }, + {0xd6da4ba1, &WrapI_CUIIU, "sceKernelCreateSema", 'i', "sxiip", HLE_KERNEL_SYSCALL }, {0x28b6489c, &WrapI_I, "sceKernelDeleteSema", 'i', "i", HLE_KERNEL_SYSCALL }, {0x3f53e640, &WrapI_II, "sceKernelSignalSema", 'i', "ii", HLE_KERNEL_SYSCALL }, {0x4e3a1105, &WrapI_IIU, "sceKernelWaitSema", 'i', "iix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED | HLE_KERNEL_SYSCALL}, diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index f584684cbb..83657cfbf0 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -45,11 +45,16 @@ struct KernelHeap : public KernelObject { static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) { u32 allocSize = (size + 3) & ~3; - // TODO: partitionId should probably decide if we allocate from userMemory or kernel or whatever... - u32 addr = userMemory.Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap"); + BlockAllocator *allocator = BlockAllocatorFromAddr(partitionId); + // TODO: Validate error code. + if (!allocator) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + + // TODO: This should probably actually use flags? Name? + u32 addr = allocator->Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap"); if (addr == (u32)-1) { - ERROR_LOG(HLE, "sceKernelCreateHeap(partitionId=%d): Failed to allocate %d bytes memory", partitionId, size); - return SCE_KERNEL_ERROR_NO_MEMORY; // Blind guess + // TODO: Validate error code. + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "fFailed to allocate %d bytes of memory", size); } KernelHeap *heap = new KernelHeap(); @@ -74,7 +79,7 @@ static int sceKernelAllocHeapMemory(int heapId, int size) { u32 addr = heap->alloc.Alloc(memSize, true); return hleLogSuccessInfoX(SCEKERNEL, addr); } else { - return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId); + return hleLogError(SCEKERNEL, error, "invalid heapId"); } } @@ -82,26 +87,31 @@ static int sceKernelDeleteHeap(int heapId) { u32 error; KernelHeap *heap = kernelObjects.Get(heapId, error); if (heap) { - userMemory.Free(heap->address); + // Not using heap->partitionId here for backwards compatibility with old save states. + BlockAllocator *allocator = BlockAllocatorFromAddr(heap->address); + if (allocator) + allocator->Free(heap->address); kernelObjects.Destroy(heap->uid); return hleLogSuccessInfoX(SCEKERNEL, 0); } else { - return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId); + return hleLogError(SCEKERNEL, error, "invalid heapId"); } } static u32 sceKernelPartitionTotalFreeMemSize(int partitionId) { - ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionTotalFreeMemSize(%d)", partitionId); - //Need more work #13021 - ///We ignore partitionId for now - return userMemory.GetTotalFreeBytes(); + BlockAllocator *allocator = BlockAllocatorFromID(partitionId); + // TODO: Validate error code. + if (!allocator) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogWarning(SCEKERNEL, allocator->GetTotalFreeBytes()); } static u32 sceKernelPartitionMaxFreeMemSize(int partitionId) { - ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionMaxFreeMemSize(%d)", partitionId); - //Need more work #13021 - ///We ignore partitionId for now - return userMemory.GetLargestFreeBlockSize(); + BlockAllocator *allocator = BlockAllocatorFromID(partitionId); + // TODO: Validate error code. + if (!allocator) + return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogWarning(SCEKERNEL, allocator->GetLargestFreeBlockSize()); } static u32 SysMemForKernel_536AD5E1() diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 4c91ffe529..3dadc4dc77 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -624,7 +624,8 @@ static u32 sceKernelMemcpy(u32 dst, u32 src, u32 size) DEBUG_LOG(SCEKERNEL, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); // Some games copy from executable code. We need to flush emuhack ops. - currentMIPS->InvalidateICache(src, size); + if (size != 0) + currentMIPS->InvalidateICache(src, size); bool skip = false; if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) { diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 6921ffdf26..1885552ce1 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -305,23 +305,16 @@ void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId) DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB: Resuming lock wait for callback"); } -int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) -{ +int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateMutex(): invalid name", SCE_KERNEL_ERROR_ERROR); - return SCE_KERNEL_ERROR_ERROR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (attr & ~0xBFF) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); - return SCE_KERNEL_ERROR_ILLEGAL_ATTR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); if (initialCount < 0) - return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal initial count"); if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) - return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal non-recursive count"); PSPMutex *mutex = new PSPMutex(); SceUID id = kernelObjects.Create(mutex); @@ -331,18 +324,14 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; mutex->nm.attr = attr; mutex->nm.initialCount = initialCount; - if (initialCount == 0) - { + if (initialCount == 0) { mutex->nm.lockLevel = 0; mutex->nm.lockThread = -1; - } - else + } else { __KernelMutexAcquireLock(mutex, initialCount); + } - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateMutex(%s, %08x, %d, %08x)", id, name, attr, initialCount, optionsPtr); - - if (optionsPtr != 0) - { + if (optionsPtr != 0) { u32 size = Memory::Read_U32(optionsPtr); if (size > 4) WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size); @@ -350,7 +339,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0) WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr); - return id; + return hleLogSuccessX(SCEKERNEL, id); } int sceKernelDeleteMutex(SceUID id) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index fffb16c20f..b6a759cb76 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -203,18 +203,11 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) } } -int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) -{ +int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) { if (!name) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateSema(): invalid name", SCE_KERNEL_ERROR_ERROR); - return SCE_KERNEL_ERROR_ERROR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (attr >= 0x200) - { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateSema(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); - return SCE_KERNEL_ERROR_ILLEGAL_ATTR; - } + return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); PSPSemaphore *s = new PSPSemaphore(); SceUID id = kernelObjects.Create(s); @@ -228,18 +221,17 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 s->ns.maxCount = maxVal; s->ns.numWaitThreads = 0; - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr); - - if (optionPtr != 0) - { - u32 size = Memory::Read_U32(optionPtr); - if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateSema(%s) unsupported options parameter, size = %d", name, size); + // Many games pass garbage into optionPtr, it doesn't have any options. + if (optionPtr != 0) { + if (!Memory::IsValidRange(optionPtr, 4)) + hleLogWarning(SCEKERNEL, id, "invalid options parameter"); + else if (Memory::Read_U32(optionPtr) > 4) + hleLogDebug(SCEKERNEL, id, "invalid options parameter size"); } if ((attr & ~PSP_SEMA_ATTR_PRIORITY) != 0) WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateSema(%s) unsupported attr parameter: %08x", name, attr); - return id; + return hleLogSuccessX(SCEKERNEL, id); } int sceKernelDeleteSema(SceUID id) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index f717cd5a3e..995ead9667 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1466,7 +1466,7 @@ void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled) { } // Loads a CPU context -void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled) { +void __KernelLoadContext(const PSPThreadContext *ctx, bool vfpuEnabled) { // r and f are immediately next to each other and must be. memcpy((void *)currentMIPS->r, (void *)ctx->r, sizeof(ctx->r) + sizeof(ctx->f)); @@ -1644,7 +1644,7 @@ void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason) t->nt.waitType = WAITTYPE_NONE; t->nt.waitID = 0; } else { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelStopThread: thread %d does not exist", threadID); + ERROR_LOG_REPORT(SCEKERNEL, "__KernelStopThread: thread %d does not exist (%s)", threadID, reason ? reason : "?"); } } diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index b7e77c95b9..70c380245d 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -177,7 +177,7 @@ bool KernelIsThreadDormant(SceUID threadID); bool KernelIsThreadWaiting(SceUID threadID); void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled); -void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled); +void __KernelLoadContext(const PSPThreadContext *ctx, bool vfpuEnabled); u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval); // can return an error value u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval); diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 63efc53eda..ce26b208ac 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -71,7 +71,7 @@ KernelObject *__KernelVTimerObject() { return new VTimer; } -static u64 __getVTimerRunningTime(VTimer *vt) { +static u64 __getVTimerRunningTime(const VTimer *vt) { if (vt->nvt.active == 0) return 0; diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index 3dac7acacd..38c288e950 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -60,9 +60,9 @@ static u32 sceMp4Finish() return 0; } -static u32 sceMp4Create(u32 mp4, u32 unknown2, u32 readBufferAddr, u32 readBufferSize) +static u32 sceMp4Create(u32 mp4, u32 callbacks, u32 readBufferAddr, u32 readBufferSize) { - ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,unknown2 %08x,readBufferAddr %08x,readBufferSize %i)", mp4, unknown2, readBufferAddr, readBufferSize); + ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,callbacks %08x,readBufferAddr %08x,readBufferSize %i)", mp4, callbacks, readBufferAddr, readBufferSize); return 0; } @@ -395,6 +395,16 @@ static u32 sceAacResetPlayPosition(u32 id) return ctx->AuResetPlayPosition(); } +static u32 mp4msv_3C2183C7(u32 unknown1, u32 unknown2) { + ERROR_LOG(ME, "UNIMPL mp4msv_3C2183C7(%d, %x)", unknown1, unknown2); + return 0; +} + +static u32 mp4msv_9CA13D1A(u32 unknown1, u32 unknown2) { + ERROR_LOG(ME, "UNIMPL mp4msv_9CA13D1A(%d, %x)", unknown1, unknown2); + return 0; +} + const HLEFunction sceMp4[] = { {0X68651CBC, &WrapU_V, "sceMp4Init", 'x', "" }, @@ -455,8 +465,19 @@ const HLEFunction sceAac[] = { {0XD2DA2BBA, &WrapU_U, "sceAacResetPlayPosition", 'x', "x" }, }; +const HLEFunction mp4msv[] = { + {0x3C2183C7, &WrapU_UU, "mp4msv_3C2183C7", 'x', "xx" }, + {0x9CA13D1A, &WrapU_UU, "mp4msv_9CA13D1A", 'x', "xx" }, + +}; + void Register_sceMp4() { RegisterModule("sceMp4", ARRAY_SIZE(sceMp4), sceMp4); - RegisterModule("sceAac", ARRAY_SIZE(sceAac), sceAac); + RegisterModule("sceAac", ARRAY_SIZE(sceAac), sceAac); +} + +void Register_mp4msv() +{ + RegisterModule("mp4msv", ARRAY_SIZE(mp4msv), mp4msv); } diff --git a/Core/HLE/sceMp4.h b/Core/HLE/sceMp4.h index b6870b90e2..9df50ed96f 100644 --- a/Core/HLE/sceMp4.h +++ b/Core/HLE/sceMp4.h @@ -25,3 +25,4 @@ enum { void Register_sceMp4(); void __AACShutdown(); void __AACDoState(PointerWrap &p); +void Register_mp4msv(); diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 3192e443b1..e96ae6ebe8 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -314,7 +314,7 @@ static u32 getMpegVersion(u32 mpegRawVersion) { } } -static void AnalyzeMpeg(u8 *buffer, u32 validSize, MpegContext *ctx) { +static void AnalyzeMpeg(const u8 *buffer, u32 validSize, MpegContext *ctx) { ctx->mpegMagic = *(u32_le*)buffer; ctx->mpegRawVersion = *(u32_le*)(buffer + PSMF_STREAM_VERSION_OFFSET); ctx->mpegVersion = getMpegVersion(ctx->mpegRawVersion); @@ -883,11 +883,11 @@ public: } }; - void add(H264Frames *p){ + void add(const H264Frames *p) { add(p->stream, p->size); }; - void add(u8* str, int sz){ + void add(const u8 *str, int sz) { int newsize = size + sz; u8* newstream = new u8[newsize]; // join two streams @@ -2173,51 +2173,41 @@ static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int u8 *Cb = Y + sizeY; u8 *Cr = Cb + sizeCb; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; x += 4) { - u32 abgr0 = imageBuffer[x + 0]; - u32 abgr1 = imageBuffer[x + 1]; - u32 abgr2 = imageBuffer[x + 2]; - u32 abgr3 = imageBuffer[x + 3]; + for (int y = 0; y < height; y += 2) { + for (int x = 0; x < width; x += 2) { + u32 abgr0 = imageBuffer[width * (y + 0) + x + 0]; + u32 abgr1 = imageBuffer[width * (y + 0) + x + 1]; + u32 abgr2 = imageBuffer[width * (y + 1) + x + 0]; + u32 abgr3 = imageBuffer[width * (y + 1) + x + 1]; u32 yCbCr0 = convertABGRToYCbCr(abgr0); u32 yCbCr1 = convertABGRToYCbCr(abgr1); u32 yCbCr2 = convertABGRToYCbCr(abgr2); u32 yCbCr3 = convertABGRToYCbCr(abgr3); - Y[x + 0] = (yCbCr0 >> 16) & 0xFF; - Y[x + 1] = (yCbCr1 >> 16) & 0xFF; - Y[x + 2] = (yCbCr2 >> 16) & 0xFF; - Y[x + 3] = (yCbCr3 >> 16) & 0xFF; + Y[width * (y + 0) + x + 0] = (yCbCr0 >> 16) & 0xFF; + Y[width * (y + 0) + x + 1] = (yCbCr1 >> 16) & 0xFF; + Y[width * (y + 1) + x + 0] = (yCbCr2 >> 16) & 0xFF; + Y[width * (y + 1) + x + 1] = (yCbCr3 >> 16) & 0xFF; - *Cb++ = (yCbCr0 >> 8) & 0xFF; - *Cr++ = yCbCr0 & 0xFF; + Cb[(width >> 1) * (y >> 1) + (x >> 1)] = (yCbCr0 >> 8) & 0xFF; + Cr[(width >> 1) * (y >> 1) + (x >> 1)] = yCbCr0 & 0xFF; } - imageBuffer += width; - Y += width ; } return (width << 16) | height; } -static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 unknown1, int unknown2) -{ - if (!Memory::IsValidAddress(bufferOutputAddr)) { - ERROR_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): invalid addresses", mpeg, bufferOutputAddr, unknown1, unknown2); - return -1; - } +static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 bufferAddr, int unknown2) { + if (!Memory::IsValidAddress(bufferOutputAddr)) + return hleLogError(ME, ERROR_MPEG_INVALID_VALUE, "invalid addresses"); MpegContext *ctx = getMpegCtx(mpeg); - if (!ctx) { - WARN_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, bufferOutputAddr, unknown1, unknown2); - return -1; - } + if (!ctx) + return hleLogWarning(ME, -1, "bad mpeg handle"); - if (ctx->mediaengine->m_buffer == 0){ - WARN_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): m_buffer is zero ", mpeg, bufferOutputAddr, unknown1, unknown2); - return ERROR_MPEG_AVC_INVALID_VALUE; - } + if (ctx->mediaengine->m_buffer == 0) + return hleLogWarning(ME, ERROR_MPEG_AVC_INVALID_VALUE, "m_buffer is zero"); - DEBUG_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x)", mpeg, bufferOutputAddr, unknown1, unknown2); const u8 *data = ctx->mediaengine->getFrameImage(); int width = ctx->mediaengine->m_desWidth; int height = ctx->mediaengine->m_desHeight; @@ -2225,7 +2215,7 @@ static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 unknown if (data) { __MpegAvcConvertToYuv420(data, bufferOutputAddr, width, height); } - return 0; + return hleLogSuccessX(ME, (width << 16) | height); } static int sceMpegGetUserdataAu(u32 mpeg, u32 streamUid, u32 auAddr, u32 resultAddr) @@ -2397,7 +2387,7 @@ const HLEFunction sceMpeg[] = {0X8160A2FE, &WrapU_U, "sceMpegAvcResourceFinish", 'x', "x" }, {0XAF26BB01, &WrapU_U, "sceMpegAvcResourceGetAvcEsBuf", 'x', "x" }, {0XFCBDB5AD, &WrapU_U, "sceMpegAvcResourceInit", 'x', "x" }, - {0XF5E7EA31, &WrapI_UUUI, "sceMpegAvcConvertToYuv420", 'i', "xxxi" }, + {0XF5E7EA31, &WrapI_UUUI, "sceMpegAvcConvertToYuv420", 'x', "xxxi" }, {0X01977054, &WrapI_UUUU, "sceMpegGetUserdataAu", 'i', "xxxx" }, {0X3C37A7A6, &WrapU_UU, "sceMpegNextAvcRpAu", 'x', "xx" }, {0X11F95CF1, &WrapU_U, "sceMpegGetAvcNalAu", 'x', "x" }, diff --git a/Core/HLE/scePsmf.cpp b/Core/HLE/scePsmf.cpp index eebac79bfa..f4bcb09166 100644 --- a/Core/HLE/scePsmf.cpp +++ b/Core/HLE/scePsmf.cpp @@ -751,7 +751,7 @@ static void DelayPsmfStateChange(u32 psmfPlayer, u32 newState, s64 delayUs) { } static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) { - if (!Memory::IsValidAddress(psmfData) || !Memory::IsValidAddress(psmfData)) { + if (!Memory::IsValidAddress(psmfStruct) || !Memory::IsValidAddress(psmfData)) { // Crashes on a PSP. return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); } diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index b205ed956d..64896ed0fe 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -886,9 +886,14 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) break; case PSP_SYSTEMPARAM_ID_INT_LANGUAGE: param = g_Config.iLanguage; + if (PSP_CoreParameter().compat.flags().EnglishOrJapaneseOnly) { + if (param != PSP_SYSTEMPARAM_LANGUAGE_ENGLISH && param != PSP_SYSTEMPARAM_LANGUAGE_JAPANESE) { + param = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + } + } break; case PSP_SYSTEMPARAM_ID_INT_BUTTON_PREFERENCE: - param = g_Config.iButtonPreference; + param = PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm ? PSP_SYSTEMPARAM_BUTTON_CIRCLE : g_Config.iButtonPreference; break; case PSP_SYSTEMPARAM_ID_INT_LOCK_PARENTAL_LEVEL: param = g_Config.iLockParentalLevel; diff --git a/Core/HW/AsyncIOManager.cpp b/Core/HW/AsyncIOManager.cpp index 1d4ce89b0a..85a9886053 100644 --- a/Core/HW/AsyncIOManager.cpp +++ b/Core/HW/AsyncIOManager.cpp @@ -134,7 +134,7 @@ void AsyncIOManager::Read(u32 handle, u8 *buf, size_t bytes, u32 invalidateAddr) EventResult(handle, AsyncIOResult(result, usec, invalidateAddr)); } -void AsyncIOManager::Write(u32 handle, u8 *buf, size_t bytes) { +void AsyncIOManager::Write(u32 handle, const u8 *buf, size_t bytes) { int usec = 0; s64 result = pspFileSystem.WriteFile(handle, buf, bytes, usec); EventResult(handle, AsyncIOResult(result, usec)); diff --git a/Core/HW/AsyncIOManager.h b/Core/HW/AsyncIOManager.h index 4b1e0b5276..59d50050cf 100644 --- a/Core/HW/AsyncIOManager.h +++ b/Core/HW/AsyncIOManager.h @@ -98,7 +98,7 @@ private: bool PopResult(u32 handle, AsyncIOResult &result); bool ReadResult(u32 handle, AsyncIOResult &result); void Read(u32 handle, u8 *buf, size_t bytes, u32 invalidateAddr); - void Write(u32 handle, u8 *buf, size_t bytes); + void Write(u32 handle, const u8 *buf, size_t bytes); void EventResult(u32 handle, AsyncIOResult result); diff --git a/Core/HW/Camera.cpp b/Core/HW/Camera.cpp index 3b99eab646..9cf8138e21 100644 --- a/Core/HW/Camera.cpp +++ b/Core/HW/Camera.cpp @@ -60,7 +60,11 @@ void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inForm void __cameraDummyImage(int width, int height, unsigned char** outData, int* outLen) { #ifdef USE_FFMPEG - unsigned char* rgbData = (unsigned char*)malloc(3 * width * height); + unsigned char *rgbData = (unsigned char *)malloc(3 * width * height); + if (!rgbData) { + *outData = nullptr; + return; + } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { rgbData[3 * (y * width + x) + 0] = x*255/width; diff --git a/Core/HW/MpegDemux.cpp b/Core/HW/MpegDemux.cpp index 4dce9cff05..6dbfa5ec44 100644 --- a/Core/HW/MpegDemux.cpp +++ b/Core/HW/MpegDemux.cpp @@ -288,7 +288,7 @@ bool MpegDemux::demux(int audioChannel) return looksValid; } -static bool isHeader(u8* audioStream, int offset) +static bool isHeader(const u8 *audioStream, int offset) { const u8 header1 = (u8)0x0F; const u8 header2 = (u8)0xD0; diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 8db47c77b5..0a19d92f85 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -120,7 +120,7 @@ bool SimpleAudio::OpenCodec(int block_align) { #endif // USE_FFMPEG } -void SimpleAudio::SetExtraData(u8 *data, int size, int wav_bytes_per_packet) { +void SimpleAudio::SetExtraData(const u8 *data, int size, int wav_bytes_per_packet) { #ifdef USE_FFMPEG if (codecCtx_) { codecCtx_->extradata = (uint8_t *)av_mallocz(size); diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 533172aaa6..ec792c9031 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -53,7 +53,7 @@ public: int GetAudioCodecID(int audioType); // Get audioCodecId from audioType // Not save stated, only used by UI. Used for ATRAC3 (non+) files. - void SetExtraData(u8 *data, int size, int wav_bytes_per_packet); + void SetExtraData(const u8 *data, int size, int wav_bytes_per_packet); void SetChannels(int channels); diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index b0a3b69c7e..a853b69dfa 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -304,6 +304,13 @@ static const KeyMap_IntStrPair key_names[] = { {NKCODE_EXT_MOUSEWHEEL_UP, "MWheelU"}, {NKCODE_EXT_MOUSEWHEEL_DOWN, "MWheelD"}, + + {NKCODE_EXT_MOTION_UP, "MotionUp"}, + {NKCODE_EXT_MOTION_DOWN, "MotionDown"}, + {NKCODE_EXT_MOTION_LEFT, "MotionLeft"}, + {NKCODE_EXT_MOTION_RIGHT, "MotionRight"}, + {NKCODE_EXT_MOTION_FORWARD, "MotionFwd"}, + {NKCODE_START_QUESTION, "¿"}, {NKCODE_LEFTBRACE, "{"}, {NKCODE_RIGHTBRACE, "}"}, @@ -399,10 +406,15 @@ const KeyMap_IntStrPair psp_button_names[] = { {VIRTKEY_ANALOG_ROTATE_CW, "Rotate Analog (CW)"}, {VIRTKEY_ANALOG_ROTATE_CCW, "Rotate Analog (CCW)"}, +#ifdef OPENXR + {VIRTKEY_VR_CAMERA_ADJUST, "VR camera adjust"}, + {VIRTKEY_VR_CAMERA_RESET, "VR camera reset"}, +#else {VIRTKEY_SCREEN_ROTATION_VERTICAL, "Display Portrait"}, {VIRTKEY_SCREEN_ROTATION_VERTICAL180, "Display Portrait Reversed"}, {VIRTKEY_SCREEN_ROTATION_HORIZONTAL, "Display Landscape"}, {VIRTKEY_SCREEN_ROTATION_HORIZONTAL180, "Display Landscape Reversed"}, +#endif {CTRL_HOME, "Home"}, {CTRL_HOLD, "Hold"}, @@ -656,7 +668,7 @@ void RestoreDefault() { g_controllerMap.clear(); g_controllerMapGeneration++; - if (IsVRBuild()) { + if (IsVREnabled()) { SetDefaultKeyMap(DEFAULT_MAPPING_VR_HEADSET, false); return; } diff --git a/Core/KeyMap.h b/Core/KeyMap.h index a8ae9f672a..c81958ab26 100644 --- a/Core/KeyMap.h +++ b/Core/KeyMap.h @@ -68,6 +68,8 @@ enum { VIRTKEY_SCREEN_ROTATION_HORIZONTAL = 0x40000022, VIRTKEY_SCREEN_ROTATION_HORIZONTAL180 = 0x40000023, VIRTKEY_SPEED_ANALOG = 0x40000024, + VIRTKEY_VR_CAMERA_ADJUST = 0x40000025, + VIRTKEY_VR_CAMERA_RESET = 0x40000026, VIRTKEY_LAST, VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; diff --git a/Core/KeyMapDefaults.cpp b/Core/KeyMapDefaults.cpp index d6d21639cb..8fc2c19a42 100644 --- a/Core/KeyMapDefaults.cpp +++ b/Core/KeyMapDefaults.cpp @@ -128,6 +128,8 @@ static const DefMappingStruct defaultXInputKeyMap[] = { {VIRTKEY_SPEED_TOGGLE, NKCODE_BUTTON_THUMBR}, {VIRTKEY_PAUSE , JOYSTICK_AXIS_LTRIGGER, +1}, {VIRTKEY_PAUSE, NKCODE_HOME}, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_GAS, +1}, + {VIRTKEY_PAUSE , JOYSTICK_AXIS_BRAKE, +1}, }; static const DefMappingStruct defaultShieldKeyMap[] = { @@ -188,6 +190,8 @@ static const DefMappingStruct defaultAndroidXboxControllerMap[] = { {CTRL_RTRIGGER , NKCODE_BUTTON_R1}, {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_RTRIGGER, +1}, {VIRTKEY_PAUSE , JOYSTICK_AXIS_LTRIGGER, +1}, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_GAS, +1}, + {VIRTKEY_PAUSE , JOYSTICK_AXIS_BRAKE, +1}, {VIRTKEY_AXIS_X_MIN, JOYSTICK_AXIS_X, -1}, {VIRTKEY_AXIS_X_MAX, JOYSTICK_AXIS_X, +1}, {VIRTKEY_AXIS_Y_MIN, JOYSTICK_AXIS_Y, +1}, @@ -242,6 +246,8 @@ static const DefMappingStruct defaultPadMapAndroid[] = { {VIRTKEY_FASTFORWARD , NKCODE_BUTTON_R2}, {VIRTKEY_PAUSE , JOYSTICK_AXIS_LTRIGGER, +1}, {VIRTKEY_PAUSE , NKCODE_BUTTON_L2 }, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_GAS, +1}, + {VIRTKEY_PAUSE , JOYSTICK_AXIS_BRAKE, +1}, {VIRTKEY_AXIS_X_MIN, JOYSTICK_AXIS_X, -1}, {VIRTKEY_AXIS_X_MAX, JOYSTICK_AXIS_X, +1}, {VIRTKEY_AXIS_Y_MIN, JOYSTICK_AXIS_Y, +1}, diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 37722fe0cf..5657bd281c 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -392,8 +392,8 @@ bool UmdReplace(const Path &filepath, std::string &error) { FileLoader *loadedFile = ConstructFileLoader(filepath); if (!loadedFile->Exists()) { - delete loadedFile; error = loadedFile->GetPath().ToVisualString() + " doesn't exist"; + delete loadedFile; return false; } UpdateLoadedFile(loadedFile); diff --git a/Core/Loaders.h b/Core/Loaders.h index fa6c637d9e..2bef2858f5 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -94,7 +94,7 @@ public: class ProxiedFileLoader : public FileLoader { public: ProxiedFileLoader(FileLoader *backend) : backend_(backend) {} - ~ProxiedFileLoader() override { + ~ProxiedFileLoader() { // Takes ownership. delete backend_; } diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index 008d24eefe..f90dd237ec 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -71,8 +71,8 @@ namespace MIPSComp { using namespace ArmJitConstants; void ArmJit::GenerateFixedCode() { + BeginWrite(GetMemoryProtectPageSize()); const u8 *start = AlignCodePage(); - BeginWrite(); // LR == SCRATCHREG2 on ARM32 so it needs to be pushed. restoreRoundingMode = AlignCode16(); { diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 0b5bf067f8..01bf94203e 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -24,6 +24,7 @@ #include "Common/CPUDetect.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/ARM/ArmJit.h" #include "Core/MIPS/ARM/ArmRegCache.h" diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 0f138c6092..238ce2e94d 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -33,6 +33,7 @@ #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/MIPSTables.h" @@ -182,9 +183,10 @@ void ArmJit::ClearCache() GenerateFixedCode(); } -void ArmJit::InvalidateCacheAt(u32 em_address, int length) -{ - blocks.InvalidateICache(em_address, length); +void ArmJit::InvalidateCacheAt(u32 em_address, int length) { + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void ArmJit::EatInstruction(MIPSOpcode op) { @@ -232,7 +234,7 @@ void ArmJit::Compile(u32 em_address) { ClearCache(); } - BeginWrite(); + BeginWrite(JitBlockCache::MAX_BLOCK_INSTRUCTIONS * 16); int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); diff --git a/Core/MIPS/ARM/ArmRegCache.h b/Core/MIPS/ARM/ArmRegCache.h index bd85cc10b2..0a405a7158 100644 --- a/Core/MIPS/ARM/ArmRegCache.h +++ b/Core/MIPS/ARM/ArmRegCache.h @@ -17,8 +17,7 @@ #pragma once -#include "../MIPS.h" -#include "../MIPSAnalyst.h" +#include "Core/MIPS/MIPS.h" #include "ArmEmitter.h" namespace ArmJitConstants { @@ -52,6 +51,10 @@ enum { } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + // R1 to R6: mapped MIPS regs // R8 = flags (maybe we could do better here?) // R9 = code pointers diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.h b/Core/MIPS/ARM/ArmRegCacheFPU.h index 3e08d719bb..f572c84a97 100644 --- a/Core/MIPS/ARM/ArmRegCacheFPU.h +++ b/Core/MIPS/ARM/ArmRegCacheFPU.h @@ -19,8 +19,7 @@ #pragma once -#include "../MIPS.h" -#include "../MIPSAnalyst.h" +#include "Core/MIPS/MIPS.h" #include "Core/MIPS/ARM/ArmRegCache.h" #include "Core/MIPS/MIPSVFPUUtils.h" #include "Common/ArmEmitter.h" @@ -46,6 +45,10 @@ enum { } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct FPURegARM { int mipsReg; // if -1, no mipsreg attached. bool isDirty; // Should the register be written back? diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index bca3f535e1..9f70435a78 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -97,8 +97,8 @@ namespace MIPSComp { using namespace Arm64JitConstants; void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { + BeginWrite(GetMemoryProtectPageSize()); const u8 *start = AlignCodePage(); - BeginWrite(); if (jo.useStaticAlloc) { saveStaticRegisters = AlignCode16(); diff --git a/Core/MIPS/ARM64/Arm64CompALU.cpp b/Core/MIPS/ARM64/Arm64CompALU.cpp index afb8d2b4a8..13a2361d86 100644 --- a/Core/MIPS/ARM64/Arm64CompALU.cpp +++ b/Core/MIPS/ARM64/Arm64CompALU.cpp @@ -24,6 +24,7 @@ #include "Common/CPUDetect.h" #include "Common/Data/Convert/SmallDataConvert.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/ARM64/Arm64Jit.h" #include "Core/MIPS/ARM64/Arm64RegCache.h" diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 8fb4c512d8..b4df4f942a 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -34,6 +34,7 @@ #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/MIPSTables.h" @@ -180,7 +181,9 @@ void Arm64Jit::ClearCache() { } void Arm64Jit::InvalidateCacheAt(u32 em_address, int length) { - blocks.InvalidateICache(em_address, length); + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void Arm64Jit::EatInstruction(MIPSOpcode op) { @@ -227,7 +230,7 @@ void Arm64Jit::Compile(u32 em_address) { ClearCache(); } - BeginWrite(4); + BeginWrite(JitBlockCache::MAX_BLOCK_INSTRUCTIONS * 16); int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); diff --git a/Core/MIPS/ARM64/Arm64RegCache.h b/Core/MIPS/ARM64/Arm64RegCache.h index 62f7771192..5528120098 100644 --- a/Core/MIPS/ARM64/Arm64RegCache.h +++ b/Core/MIPS/ARM64/Arm64RegCache.h @@ -18,7 +18,6 @@ #pragma once #include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" #include "Common/Arm64Emitter.h" namespace Arm64JitConstants { @@ -55,6 +54,10 @@ enum { } // namespace +namespace MIPSAnalyst { +struct AnalysisResults; +}; + typedef int MIPSReg; struct RegARM64 { diff --git a/Core/MIPS/ARM64/Arm64RegCacheFPU.h b/Core/MIPS/ARM64/Arm64RegCacheFPU.h index 13284d2389..657d218611 100644 --- a/Core/MIPS/ARM64/Arm64RegCacheFPU.h +++ b/Core/MIPS/ARM64/Arm64RegCacheFPU.h @@ -19,8 +19,7 @@ #pragma once -#include "../MIPS.h" -#include "../MIPSAnalyst.h" +#include "Core/MIPS/MIPS.h" #include "Core/MIPS/ARM64/Arm64RegCache.h" #include "Core/MIPS/MIPSVFPUUtils.h" #include "Common/Arm64Emitter.h" @@ -46,6 +45,10 @@ enum { } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct FPURegARM64 { int mipsReg; // if -1, no mipsreg attached. bool isDirty; // Should the register be written back? diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index 62d813f3b2..e8fe1c46b6 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -118,7 +118,7 @@ void IRFrontend::Comp_RType3(MIPSOpcode op) { MIPSGPReg rd = _RD; // noop, won't write to ZERO. - if (rd == 0) + if (rd == MIPS_REG_ZERO) return; switch (op & 63) { @@ -298,7 +298,7 @@ void IRFrontend::Comp_Allegrex2(MIPSOpcode op) { MIPSGPReg rd = _RD; // Don't change $zr. - if (rd == 0) + if (rd == MIPS_REG_ZERO) return; switch (op & 0x3ff) { diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index c0aac3f3f1..cf6b4faa75 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -118,7 +118,7 @@ void IRFrontend::Comp_FPUComp(MIPSOpcode op) { break; case 3: // ueq, ngl (equal, unordered) mode = IRFpCompareMode::EqualUnordered; - return; + break; case 4: // olt, lt (less than, ordered) mode = IRFpCompareMode::LessOrdered; break; diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 4fffc6765d..bfdcf69bed 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -72,9 +72,27 @@ namespace MIPSComp { regs[3] == regs[2] + 1; } + static bool IsVec4(VectorSize sz, const u8 regs[4]) { + return sz == V_Quad && IsConsecutive4(regs) && (regs[0] & 3) == 0; + } + + static bool IsMatrixVec4(MatrixSize sz, const u8 regs[16]) { + if (sz != M_4x4) + return false; + if (!IsConsecutive4(®s[0]) || (regs[0] & 3) != 0) + return false; + if (!IsConsecutive4(®s[4]) || (regs[4] & 3) != 0) + return false; + if (!IsConsecutive4(®s[8]) || (regs[8] & 3) != 0) + return false; + if (!IsConsecutive4(®s[12]) || (regs[12] & 3) != 0) + return false; + return true; + } + // Vector regs can overlap in all sorts of swizzled ways. // This does allow a single overlap in sregs[i]. - static bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { + static bool IsOverlapSafeAllowS(int dreg, int di, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = NULL) { for (int i = 0; i < sn; ++i) { if (sregs[i] == dreg && i != di) return false; @@ -88,7 +106,7 @@ namespace MIPSComp { return true; } - static bool IsOverlapSafeAllowS(int dn, u8 dregs[], int sn, u8 sregs[], int tn = 0, u8 tregs[] = nullptr) { + static bool IsOverlapSafeAllowS(int dn, const u8 dregs[], int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = nullptr) { for (int i = 0; i < dn; ++i) { if (!IsOverlapSafeAllowS(dregs[i], i, sn, sregs, tn, tregs)) { return false; @@ -97,11 +115,11 @@ namespace MIPSComp { return true; } - static bool IsOverlapSafe(int dreg, int sn, u8 sregs[], int tn = 0, u8 tregs[] = nullptr) { + static bool IsOverlapSafe(int dreg, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = nullptr) { return IsOverlapSafeAllowS(dreg, -1, sn, sregs, tn, tregs); } - static bool IsOverlapSafe(int dn, u8 dregs[], int sn, u8 sregs[], int tn = 0, u8 tregs[] = nullptr) { + static bool IsOverlapSafe(int dn, const u8 dregs[], int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = nullptr) { for (int i = 0; i < dn; ++i) { if (!IsOverlapSafe(dregs[i], sn, sregs, tn, tregs)) { return false; @@ -117,8 +135,9 @@ namespace MIPSComp { int abs = (prefix >> (8 + i)) & 1; int negate = (prefix >> (16 + i)) & 1; int constants = (prefix >> (12 + i)) & 1; - if (regnum < n || abs || negate || constants) { - return false; + if (regnum >= n && !constants) { + if (abs || negate || regnum != i) + return false; } } @@ -165,14 +184,14 @@ namespace MIPSComp { return; int n = GetNumVectorElements(sz); - u8 origV[4]; + u8 origV[4]{}; static const float constantArray[8] = { 0.f, 1.f, 2.f, 0.5f, 3.f, 1.f / 3.f, 0.25f, 1.f / 6.f }; for (int i = 0; i < n; i++) origV[i] = vregs[i]; // Some common vector prefixes - if (sz == V_Quad && IsConsecutive4(vregs)) { + if (IsVec4(sz, vregs)) { if (prefix == 0xF00E4) { InitRegs(vregs, tempReg); ir.Write(IROp::Vec4Neg, vregs[0], origV[0]); @@ -326,7 +345,7 @@ namespace MIPSComp { switch (op >> 26) { case 54: //lv.q - if (IsConsecutive4(vregs)) { + if (IsVec4(V_Quad, vregs)) { ir.Write(IROp::LoadVec4, vregs[0], rs, ir.AddConstant(imm)); } else { // Let's not even bother with "vertical" loads for now. @@ -340,7 +359,7 @@ namespace MIPSComp { break; case 62: //sv.q - if (IsConsecutive4(vregs)) { + if (IsVec4(V_Quad, vregs)) { ir.Write(IROp::StoreVec4, vregs[0], rs, ir.AddConstant(imm)); } else { // Let's not even bother with "vertical" stores for now. @@ -380,7 +399,7 @@ namespace MIPSComp { u8 dregs[4]; GetVectorRegsPrefixD(dregs, sz, vd); - if (sz == V_Quad && IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { ir.Write(IROp::Vec4Init, dregs[0], (int)(type == 6 ? Vec4Init::AllZERO : Vec4Init::AllONE)); } else { for (int i = 0; i < n; i++) { @@ -405,7 +424,7 @@ namespace MIPSComp { u8 dregs[4]; GetVectorRegsPrefixD(dregs, sz, vd); - if (sz == 4 && IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { int row = vd & 3; Vec4Init init = Vec4Init((int)Vec4Init::Set_1000 + row); ir.Write(IROp::Vec4Init, dregs[0], (int)init); @@ -464,6 +483,7 @@ namespace MIPSComp { init = Vec4Init::AllONE; break; default: + INVALIDOP; return; } ir.Write(IROp::Vec4Init, vec[0], (int)init); @@ -472,7 +492,7 @@ namespace MIPSComp { void IRFrontend::Comp_VHdp(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) { + if (js.HasUnknownPrefix() || js.HasSPrefix() || !IsPrefixWithinSize(js.prefixT, op)) { DISABLE; } @@ -572,7 +592,7 @@ namespace MIPSComp { GetVectorRegsPrefixT(tregs, sz, vt); GetVectorRegsPrefixD(dregs, V_Single, vd); - if (sz == V_Quad && IsConsecutive4(sregs) && IsConsecutive4(tregs) && IsOverlapSafe(dregs[0], n, sregs, n, tregs)) { + if (IsVec4(sz, sregs) && IsVec4(sz, tregs) && IsOverlapSafe(dregs[0], n, sregs, n, tregs)) { ir.Write(IROp::Vec4Dot, dregs[0], sregs[0], tregs[0]); ApplyPrefixD(dregs, V_Single); return; @@ -658,7 +678,7 @@ namespace MIPSComp { } // If all three are consecutive 4, we're safe regardless of if we use temps so we should not check that here. - if (allowSIMD && sz == V_Quad && IsConsecutive4(dregs) && IsConsecutive4(sregs) && IsConsecutive4(tregs)) { + if (allowSIMD && IsVec4(sz, dregs) && IsVec4(sz, sregs) && IsVec4(sz, tregs)) { IROp opFunc = IROp::Nop; switch (op >> 26) { case 24: //VFPU0 @@ -754,8 +774,15 @@ namespace MIPSComp { void IRFrontend::Comp_VV2Op(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) - DISABLE; + int optype = (op >> 16) & 0x1f; + if (optype == 0) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op)) + DISABLE; + } else { + // Many of these apply the D prefix strangely or override parts of the S prefix. + if (!js.HasNoPrefix()) + DISABLE; + } // Vector unary operation // d[N] = OP(s[N]) (see below) @@ -763,7 +790,6 @@ namespace MIPSComp { int vs = _VS; int vd = _VD; - int optype = (op >> 16) & 0x1f; if (optype >= 16 && !js.HasNoPrefix()) { DISABLE; } else if ((optype == 1 || optype == 2) && js.HasSPrefix()) { @@ -780,14 +806,14 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - u8 sregs[4], dregs[4]; + u8 sregs[4]{}, dregs[4]{}; GetVectorRegsPrefixS(sregs, sz, vs); GetVectorRegsPrefixD(dregs, sz, vd); bool usingTemps = false; u8 tempregs[4]; for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], n, sregs)) { + if (!IsOverlapSafeAllowS(dregs[i], i, n, sregs)) { usingTemps = true; tempregs[i] = IRVTEMP_0 + i; } else { @@ -805,7 +831,7 @@ namespace MIPSComp { break; } - if (canSIMD && !usingTemps && IsConsecutive4(sregs) && IsConsecutive4(dregs)) { + if (canSIMD && !usingTemps && IsVec4(sz, sregs) && IsVec4(sz, dregs)) { switch (optype) { case 0: // vmov ir.Write(IROp::Vec4Mov, dregs[0], sregs[0]); @@ -1185,8 +1211,8 @@ namespace MIPSComp { int vt = _VT; u8 sregs[4], dregs[4], treg; GetVectorRegsPrefixS(sregs, sz, vs); - // TODO: Prefixes seem strange... - GetVectorRegsPrefixT(&treg, V_Single, vt); + // T prefixes handled by interp. + GetVectorRegs(&treg, V_Single, vt); GetVectorRegsPrefixD(dregs, sz, vd); bool overlap = false; @@ -1203,7 +1229,7 @@ namespace MIPSComp { } } - if (n == 4 && IsConsecutive4(sregs) && IsConsecutive4(dregs)) { + if (IsVec4(sz, sregs) && IsVec4(sz, dregs)) { if (!overlap || (vs == vd && IsOverlapSafe(treg, n, dregs))) { ir.Write(IROp::Vec4Scale, dregs[0], sregs[0], treg); ApplyPrefixD(dregs, sz); @@ -1288,12 +1314,12 @@ namespace MIPSComp { // dregs are always consecutive, thanks to our transpose trick. // However, not sure this is always worth it. - if (sz == M_4x4 && IsConsecutive4(dregs)) { + if (IsMatrixVec4(sz, dregs)) { // TODO: The interpreter would like proper matrix ops better. Can generate those, and // expand them like this as needed on "real" architectures. int s0 = IRVTEMP_0; int s1 = IRVTEMP_PFX_T; - if (!IsConsecutive4(sregs)) { + if (!IsMatrixVec4(sz, sregs)) { // METHOD 1: Handles AbC and Abc for (int j = 0; j < 4; j++) { ir.Write(IROp::Vec4Scale, s0, sregs[0], tregs[j * 4]); @@ -1304,7 +1330,7 @@ namespace MIPSComp { ir.Write(IROp::Vec4Mov, dregs[j * 4], s0); } return; - } else if (IsConsecutive4(tregs)) { + } else if (IsMatrixVec4(sz, tregs)) { // METHOD 2: Handles ABC only. Not efficient on CPUs that don't do fast dots. // Dots only work if tregs are consecutive. // TODO: Skip this and resort to method one and transpose the output? @@ -1370,7 +1396,7 @@ namespace MIPSComp { GetVectorRegs(dregs, sz, _VD); // SIMD-optimized implementations - if sregs[0..3] is non-consecutive, it's transposed. - if (msz == M_4x4 && !IsConsecutive4(sregs)) { + if (msz == M_4x4 && !IsMatrixVec4(msz, sregs)) { int s0 = IRVTEMP_0; int s1 = IRVTEMP_PFX_S; // For this algorithm, we don't care if tregs are consecutive or not, @@ -1385,7 +1411,7 @@ namespace MIPSComp { ir.Write(IROp::Vec4Add, s0, s0, sregs[i]); } } - if (IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { ir.Write(IROp::Vec4Mov, dregs[0], s0); } else { for (int i = 0; i < 4; i++) { @@ -1393,7 +1419,7 @@ namespace MIPSComp { } } return; - } else if (msz == M_4x4 && IsConsecutive4(sregs)) { + } else if (msz == M_4x4 && IsMatrixVec4(msz, sregs)) { // Consecutive, which is harder. DISABLE; int s0 = IRVTEMP_0; @@ -1408,7 +1434,7 @@ namespace MIPSComp { ir.Write(IROp::Vec4Add, s0, s0, sregs[i]); } } - if (IsConsecutive4(dregs)) { + if (IsVec4(sz, dregs)) { ir.Write(IROp::Vec4Mov, dregs[0], s0); } else { for (int i = 0; i < 4; i++) { @@ -1458,7 +1484,7 @@ namespace MIPSComp { void IRFrontend::Comp_VDet(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || (js.prefixT & 0x000CFCF0) != 0x000E0) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) { DISABLE; } @@ -1508,8 +1534,8 @@ namespace MIPSComp { int nOut = GetNumVectorElements(outsize); - // If src registers aren't contiguous, make them. - if (sz == V_Quad && !IsConsecutive4(sregs)) { + // If src registers aren't contiguous, make them (mainly for bits == 8.) + if (sz == V_Quad && !IsVec4(sz, sregs)) { // T prefix is unused. for (int i = 0; i < 4; i++) { srcregs[i] = IRVTEMP_PFX_T + i; @@ -1615,7 +1641,7 @@ namespace MIPSComp { } } } else if (outsize == V_Quad) { - bool consecutive = IsConsecutive4(dregs); + bool consecutive = IsVec4(outsize, dregs); if (!consecutive || !IsOverlapSafe(nOut, dregs, nIn, srcregs)) { for (int i = 0; i < nOut; i++) { tempregs[i] = IRVTEMP_PFX_T + i; @@ -1671,7 +1697,7 @@ namespace MIPSComp { GetVectorRegs(tregs, sz, _VT); GetVectorRegs(dregs, sz, _VD); - u8 tempregs[4]; + u8 tempregs[4]{}; for (int i = 0; i < n; ++i) { if (!IsOverlapSafe(dregs[i], n, sregs, n, tregs)) { tempregs[i] = IRVTEMP_PFX_T + i; // using IRTEMP0 for other things @@ -1848,33 +1874,54 @@ namespace MIPSComp { int imm = (op >> 16) & 0x1f; VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); + int sineLane = (imm >> 2) & 3; + int cosineLane = imm & 3; bool negSin = (imm & 0x10) ? true : false; + bool broadcastSine = sineLane == cosineLane; char d[4] = { '0', '0', '0', '0' }; - if (((imm >> 2) & 3) == (imm & 3)) { + if (broadcastSine) { for (int i = 0; i < 4; i++) d[i] = 's'; } - d[(imm >> 2) & 3] = 's'; - d[imm & 3] = 'c'; + d[sineLane] = 's'; + d[cosineLane] = 'c'; u8 dregs[4]; GetVectorRegs(dregs, sz, vd); u8 sreg[1]; GetVectorRegs(sreg, V_Single, vs); + + // If there's overlap, sin is calculated without it, but cosine uses the result. + // This corresponds with prefix handling, where cosine doesn't get in prefixes. + if (broadcastSine || !IsOverlapSafe(n, dregs, 1, sreg)) { + ir.Write(IROp::FSin, IRVTEMP_0, sreg[0]); + if (negSin) + ir.Write(IROp::FNeg, IRVTEMP_0, IRVTEMP_0); + } + for (int i = 0; i < n; i++) { switch (d[i]) { case '0': ir.Write(IROp::SetConstF, dregs[i], ir.AddConstantFloat(0.0f)); break; case 's': - ir.Write(IROp::FSin, dregs[i], sreg[0]); - if (negSin) { - ir.Write(IROp::FNeg, dregs[i], dregs[i]); + if (broadcastSine || !IsOverlapSafe(n, dregs, 1, sreg)) { + ir.Write(IROp::FMov, dregs[i], IRVTEMP_0); + } else { + ir.Write(IROp::FSin, dregs[i], sreg[0]); + if (negSin) { + ir.Write(IROp::FNeg, dregs[i], dregs[i]); + } } break; case 'c': - ir.Write(IROp::FCos, dregs[i], sreg[0]); + if (IsOverlapSafe(n, dregs, 1, sreg)) + ir.Write(IROp::FCos, dregs[i], sreg[0]); + else if (dregs[sineLane] == sreg[0]) + ir.Write(IROp::FCos, dregs[i], IRVTEMP_0); + else + ir.Write(IROp::SetConstF, dregs[i], ir.AddConstantFloat(1.0f)); break; } } @@ -1882,7 +1929,7 @@ namespace MIPSComp { void IRFrontend::Comp_Vsgn(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) { DISABLE; } @@ -1978,7 +2025,7 @@ namespace MIPSComp { void IRFrontend::Comp_Vbfy(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix() || (js.prefixS & VFPU_NEGATE(1, 1, 1, 1)) != 0) { DISABLE; } diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 27b0ba0ca3..da1e643888 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -881,17 +881,23 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { break; } case IRFpCompareMode::EqualOrdered: - case IRFpCompareMode::EqualUnordered: mips->fpcond = mips->f[inst->src1] == mips->f[inst->src2]; break; + case IRFpCompareMode::EqualUnordered: + mips->fpcond = mips->f[inst->src1] == mips->f[inst->src2] || my_isnan(mips->f[inst->src1]) || my_isnan(mips->f[inst->src2]); + break; case IRFpCompareMode::LessEqualOrdered: - case IRFpCompareMode::LessEqualUnordered: mips->fpcond = mips->f[inst->src1] <= mips->f[inst->src2]; break; + case IRFpCompareMode::LessEqualUnordered: + mips->fpcond = !(mips->f[inst->src1] > mips->f[inst->src2]); + break; case IRFpCompareMode::LessOrdered: - case IRFpCompareMode::LessUnordered: mips->fpcond = mips->f[inst->src1] < mips->f[inst->src2]; break; + case IRFpCompareMode::LessUnordered: + mips->fpcond = !(mips->f[inst->src1] >= mips->f[inst->src2]); + break; } break; diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index e5aadba24b..973ddf524e 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -136,7 +136,7 @@ private: class IRJit : public JitInterface { public: IRJit(MIPSState *mipsState); - virtual ~IRJit(); + ~IRJit(); void DoState(PointerWrap &p) override; diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index f5b11ca4a5..e822c5c47d 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -304,7 +304,7 @@ bool JitBlockCache::RangeMayHaveEmuHacks(u32 start, u32 end) const { return false; } -static int binary_search(JitBlock blocks_[], const u8 *baseoff, int imin, int imax) { +static int binary_search(const JitBlock blocks_[], const u8 *baseoff, int imin, int imax) { while (imin < imax) { int imid = (imin + imax) / 2; if (blocks_[imid].normalEntry < baseoff) diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index 28a432fafe..f8836160ea 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -26,7 +26,6 @@ #include "ppsspp_config.h" #include "Common/CommonTypes.h" #include "Common/CodeBlock.h" -#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPS.h" #if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 5aeeacbbf8..9efe9fbd17 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -365,15 +365,10 @@ void MIPSState::ProcessPendingClears() { void MIPSState::InvalidateICache(u32 address, int length) { // Only really applies to jit. + // Note that the backend is responsible for ensuring native code can still be returned to. std::lock_guard guard(MIPSComp::jitLock); - if (MIPSComp::jit) { - if (coreState == CORE_RUNNING || insideJit) { - pendingClears.emplace_back(address, length); - hasPendingClears = true; - CoreTiming::ForceCheck(); - } else { - MIPSComp::jit->InvalidateCacheAt(address, length); - } + if (MIPSComp::jit && length != 0) { + MIPSComp::jit->InvalidateCacheAt(address, length); } } diff --git a/Core/MIPS/MIPS/MipsJit.cpp b/Core/MIPS/MIPS/MipsJit.cpp index 2a096759c4..2b263773c8 100644 --- a/Core/MIPS/MIPS/MipsJit.cpp +++ b/Core/MIPS/MIPS/MipsJit.cpp @@ -97,9 +97,10 @@ void MipsJit::ClearCache() //GenerateFixedCode(); } -void MipsJit::InvalidateCacheAt(u32 em_address, int length) -{ - blocks.InvalidateICache(em_address, length); +void MipsJit::InvalidateCacheAt(u32 em_address, int length) { + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void MipsJit::EatInstruction(MIPSOpcode op) { diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 09e9771c34..cdeaa6a169 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -355,6 +355,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x9f269daa6f0da803, 128, "dl_write_scissor_region", }, { 0x9f7919eeb43982b0, 208, "__fixdfsi", }, { 0xa1c9b0a2c71235bf, 1752, "marvelalliance1_copy" }, // Marvel Ultimate Alliance 1 (EU) + { 0x9b76c7f2a41aa805, 1752, "marvelalliance1_copy" }, // Marvel Ultimate alliance 1 (US) { 0xa1ca0640f11182e7, 72, "strcspn", }, { 0xa243486be51ce224, 272, "cosf", }, { 0xa2bcef60a550a3ef, 92, "matrix_rot_z", }, @@ -610,25 +611,7 @@ namespace MIPSAnalyst { int OpMemoryAccessSize(u32 pc) { const auto op = Memory::Read_Instruction(pc, true); - MIPSInfo info = MIPSGetInfo(op); - if ((info & (IN_MEM | OUT_MEM)) == 0) { - return 0; - } - - // TODO: Verify lwl/lwr/etc.? - switch (info & MEMTYPE_MASK) { - case MEMTYPE_BYTE: - return 1; - case MEMTYPE_HWORD: - return 2; - case MEMTYPE_WORD: - case MEMTYPE_FLOAT: - return 4; - case MEMTYPE_VQUAD: - return 16; - } - - return 0; + return MIPSGetMemoryAccessSize(op); } bool IsOpMemoryWrite(u32 pc) { @@ -1552,21 +1535,7 @@ skip: // lw, sh, ... if (!IsSyscall(op) && (opInfo & (IN_MEM | OUT_MEM)) != 0) { info.isDataAccess = true; - switch (opInfo & MEMTYPE_MASK) { - case MEMTYPE_BYTE: - info.dataSize = 1; - break; - case MEMTYPE_HWORD: - info.dataSize = 2; - break; - case MEMTYPE_WORD: - case MEMTYPE_FLOAT: - info.dataSize = 4; - break; - - case MEMTYPE_VQUAD: - info.dataSize = 16; - } + info.dataSize = MIPSGetMemoryAccessSize(op); u32 rs = cpu->GetRegValue(0, (int)MIPS_GET_RS(op)); s16 imm16 = op & 0xFFFF; diff --git a/Core/MIPS/MIPSDebugInterface.cpp b/Core/MIPS/MIPSDebugInterface.cpp index f81b55ca98..bffdee83b6 100644 --- a/Core/MIPS/MIPSDebugInterface.cpp +++ b/Core/MIPS/MIPSDebugInterface.cpp @@ -159,37 +159,25 @@ public: return EXPR_TYPE_UINT; } - bool getMemoryValue(uint32_t address, int size, uint32_t& dest, char* error) override - { - switch (size) - { - case 1: case 2: case 4: - break; - default: - sprintf(error,"Invalid memory access size %d",size); - return false; - } + bool getMemoryValue(uint32_t address, int size, uint32_t& dest, char* error) override { + // We allow, but ignore, bad access. + // If we didn't, log/condition statements that reference registers couldn't be configured. + bool valid = Memory::IsValidRange(address, size); - if (address % size) - { - sprintf(error,"Invalid memory access (unaligned)"); - return false; - } - - switch (size) - { + switch (size) { case 1: - dest = Memory::Read_U8(address); - break; + dest = valid ? Memory::Read_U8(address) : 0; + return true; case 2: - dest = Memory::Read_U16(address); - break; + dest = valid ? Memory::Read_U16(address) : 0; + return true; case 4: - dest = Memory::Read_U32(address); - break; + dest = valid ? Memory::Read_U32(address) : 0; + return true; } - return true; + sprintf(error, "Unexpected memory access size %d", size); + return false; } private: diff --git a/Core/MIPS/MIPSDebugInterface.h b/Core/MIPS/MIPSDebugInterface.h index 088256e802..03324a36c2 100644 --- a/Core/MIPS/MIPSDebugInterface.h +++ b/Core/MIPS/MIPSDebugInterface.h @@ -48,7 +48,6 @@ public: //overridden functions const char *GetName() override; - int GetGPRSize() override { return GPR_SIZE_32; } u32 GetGPR32Value(int reg) override { return cpu->r[reg]; } u32 GetPC() override { return cpu->pc; } u32 GetLR() override { return cpu->r[MIPS_REG_RA]; } diff --git a/Core/MIPS/MIPSInt.h b/Core/MIPS/MIPSInt.h index cd52fc409b..039a5f597f 100644 --- a/Core/MIPS/MIPSInt.h +++ b/Core/MIPS/MIPSInt.h @@ -23,8 +23,6 @@ int MIPS_SingleStep(); namespace MIPSInt { - void Int_Unknown(MIPSOpcode op); - void Int_Unimpl(MIPSOpcode op); void Int_Syscall(MIPSOpcode op); void Int_mxc1(MIPSOpcode op); diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index c8df6b21dc..1b2c8d60ec 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -540,8 +540,10 @@ namespace MIPSInt ApplySwizzleS(&s[(n - 1) * 4], V_Quad); // T prefix applies only for the last row, and is used per element. // This is like vscl, but instead of zzzz it uses xxxx. + int tlane = (vt >> 5) & 3; + t[tlane] = t[0]; u32 tprefixRemove = VFPU_ANY_SWIZZLE(); - u32 tprefixAdd = VFPU_SWIZZLE(0, 0, 0, 0); + u32 tprefixAdd = VFPU_SWIZZLE(tlane, tlane, tlane, tlane); ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); for (int b = 0; b < n; b++) { @@ -1518,9 +1520,10 @@ namespace MIPSInt // T prefix forces swizzle (zzzz for some reason, so we force V_Quad.) // That means negate still works, but constants are a bit weird. - t[2] = V(vt); + int tlane = (vt >> 5) & 3; + t[tlane] = V(vt); u32 tprefixRemove = VFPU_ANY_SWIZZLE(); - u32 tprefixAdd = VFPU_SWIZZLE(2, 2, 2, 2); + u32 tprefixAdd = VFPU_SWIZZLE(tlane, tlane, tlane, tlane); ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); int n = GetNumVectorElements(sz); @@ -1607,10 +1610,28 @@ namespace MIPSInt } else { d[sineLane] = sine; } - d[cosineLane] = cosine; - // D prefix works, just not for x. - currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFEFC; + if (((vd >> 2) & 7) == ((vs >> 2) & 7)) { + u8 dregs[4]{}; + GetVectorRegs(dregs, sz, vd); + // Calculate cosine based on sine/zero result. + bool written = false; + for (int i = 0; i < 4; i++) { + if (vs == dregs[i]) { + d[cosineLane] = vfpu_cos(d[i]); + written = true; + break; + } + } + if (!written) + d[cosineLane] = cosine; + } else { + d[cosineLane] = cosine; + } + + // D prefix works, just not for the cosine lane. + uint32_t dprefixRemove = (3 << cosineLane) | (1 << (8 + cosineLane)); + currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFFFF ^ dprefixRemove; ApplyPrefixD(d, sz); WriteVector(d, sz, vd); PC += 4; diff --git a/Core/MIPS/MIPSIntVFPU.h b/Core/MIPS/MIPSIntVFPU.h index 1d0a1ba1f1..fdd7954aa3 100644 --- a/Core/MIPS/MIPSIntVFPU.h +++ b/Core/MIPS/MIPSIntVFPU.h @@ -26,7 +26,6 @@ namespace MIPSInt void Int_SV(MIPSOpcode op); void Int_SVQ(MIPSOpcode op); void Int_Mftv(MIPSOpcode op); - void Int_MatrixSet(MIPSOpcode op); void Int_VecDo3(MIPSOpcode op); void Int_Vcst(MIPSOpcode op); void Int_VMatrixInit(MIPSOpcode op); diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 6a411f42ba..996a54daf7 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -938,8 +938,7 @@ void MIPSDisAsm(MIPSOpcode op, u32 pc, char *out, bool tabsToSpaces) { } } -void MIPSInterpret(MIPSOpcode op) { - const MIPSInstruction *instr = MIPSGetInstruction(op); +static inline void Interpret(const MIPSInstruction *instr, MIPSOpcode op) { if (instr && instr->interpret) { instr->interpret(op); } else { @@ -947,70 +946,116 @@ void MIPSInterpret(MIPSOpcode op) { // Try to disassemble it char disasm[256]; MIPSDisAsm(op, currentMIPS->pc, disasm); - _dbg_assert_msg_( 0, "%s", disasm); + _dbg_assert_msg_(0, "%s", disasm); currentMIPS->pc += 4; } } +inline int GetInstructionCycleEstimate(const MIPSInstruction *instr) { + if (instr) + return instr->flags.cycles; + return 1; +} + +void MIPSInterpret(MIPSOpcode op) { + const MIPSInstruction *instr = MIPSGetInstruction(op); + Interpret(instr, op); +} + #define _RS ((op>>21) & 0x1F) #define _RT ((op>>16) & 0x1F) #define _RD ((op>>11) & 0x1F) #define R(i) (curMips->r[i]) - -int MIPSInterpret_RunUntil(u64 globalTicks) -{ +static inline void RunUntilFast() { MIPSState *curMips = currentMIPS; - while (coreState == CORE_RUNNING) - { + // NEVER stop in a delay slot! + while (curMips->downcount >= 0 && coreState == CORE_RUNNING) { + do { + // Replacements and similar are processed here, intentionally. + MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); + + bool wasInDelaySlot = curMips->inDelaySlot; + const MIPSInstruction *instr = MIPSGetInstruction(op); + Interpret(instr, op); + curMips->downcount -= GetInstructionCycleEstimate(instr); + + // The reason we have to check this is the delay slot hack in Int_Syscall. + if (curMips->inDelaySlot && wasInDelaySlot) { + curMips->pc = curMips->nextPC; + curMips->inDelaySlot = false; + } + } while (curMips->inDelaySlot); + } +} + +static void RunUntilWithChecks(u64 globalTicks) { + MIPSState *curMips = currentMIPS; + // NEVER stop in a delay slot! + bool hasBPs = CBreakPoints::HasBreakPoints(); + bool hasMCs = CBreakPoints::HasMemChecks(); + while (curMips->downcount >= 0 && coreState == CORE_RUNNING) { + do { + // Replacements and similar are processed here, intentionally. + MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); + const MIPSInstruction *instr = MIPSGetInstruction(op); + + // Check for breakpoint + if (hasBPs && CBreakPoints::IsAddressBreakPoint(curMips->pc) && CBreakPoints::CheckSkipFirst() != curMips->pc) { + auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); + if (!cond || cond->Evaluate()) { + Core_EnableStepping(true, "cpu.breakpoint", curMips->pc); + if (CBreakPoints::IsTempBreakPoint(curMips->pc)) + CBreakPoints::RemoveBreakPoint(curMips->pc); + break; + } + } + if (hasMCs && (instr->flags & (IN_MEM | OUT_MEM)) != 0 && CBreakPoints::CheckSkipFirst() != curMips->pc && instr->interpret != &Int_Syscall) { + // This is common for all IN_MEM/OUT_MEM funcs. + int offset = (instr->flags & IS_VFPU) != 0 ? SignExtend16ToS32(op & 0xFFFC) : SignExtend16ToS32(op); + u32 addr = (R(_RS) + offset) & 0xFFFFFFFC; + int sz = MIPSGetMemoryAccessSize(op); + + if ((instr->flags & IN_MEM) != 0) + CBreakPoints::ExecMemCheck(addr, false, sz, curMips->pc, "interpret"); + if ((instr->flags & OUT_MEM) != 0) + CBreakPoints::ExecMemCheck(addr, true, sz, curMips->pc, "interpret"); + + // If it tripped, bail without running. + if (coreState == CORE_STEPPING) + break; + } + + bool wasInDelaySlot = curMips->inDelaySlot; + Interpret(instr, op); + curMips->downcount -= GetInstructionCycleEstimate(instr); + + // The reason we have to check this is the delay slot hack in Int_Syscall. + if (curMips->inDelaySlot && wasInDelaySlot) { + curMips->pc = curMips->nextPC; + curMips->inDelaySlot = false; + } + } while (curMips->inDelaySlot); + + if (CoreTiming::GetTicks() > globalTicks) + return; + } +} + +int MIPSInterpret_RunUntil(u64 globalTicks) { + MIPSState *curMips = currentMIPS; + while (coreState == CORE_RUNNING) { CoreTiming::Advance(); - // NEVER stop in a delay slot! - while (curMips->downcount >= 0 && coreState == CORE_RUNNING) - { - // int cycles = 0; - { - again: - MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc)); - //MIPSOpcode op = Memory::Read_Opcode_JIT(mipsr4k.pc); + uint64_t ticksLeft = globalTicks - CoreTiming::GetTicks(); + if (CBreakPoints::HasBreakPoints() || CBreakPoints::HasMemChecks() || ticksLeft <= curMips->downcount) + RunUntilWithChecks(globalTicks); + else + RunUntilFast(); - //2: check for breakpoint (VERY SLOW) -#if defined(_DEBUG) - if (CBreakPoints::IsAddressBreakPoint(curMips->pc)) - { - auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); - if (!cond || cond->Evaluate()) - { - Core_EnableStepping(true, "cpu.breakpoint", curMips->pc); - if (CBreakPoints::IsTempBreakPoint(curMips->pc)) - CBreakPoints::RemoveBreakPoint(curMips->pc); - break; - } - } -#endif - - bool wasInDelaySlot = curMips->inDelaySlot; - MIPSInterpret(op); - curMips->downcount -= MIPSGetInstructionCycleEstimate(op); - - if (curMips->inDelaySlot) - { - // The reason we have to check this is the delay slot hack in Int_Syscall. - if (wasInDelaySlot) - { - curMips->pc = curMips->nextPC; - curMips->inDelaySlot = false; - continue; - } - goto again; - } - } - - if (CoreTiming::GetTicks() > globalTicks) - { - // DEBUG_LOG(CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks()); - return 1; - } + if (CoreTiming::GetTicks() > globalTicks) { + // DEBUG_LOG(CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks()); + return 1; } } @@ -1049,8 +1094,29 @@ MIPSInterpretFunc MIPSGetInterpretFunc(MIPSOpcode op) // TODO: Do something that makes sense here. int MIPSGetInstructionCycleEstimate(MIPSOpcode op) { + const MIPSInstruction *instr = MIPSGetInstruction(op); + return GetInstructionCycleEstimate(instr); +} + +int MIPSGetMemoryAccessSize(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); - return info.cycles; + if ((info & (IN_MEM | OUT_MEM)) == 0) { + return 0; + } + + switch (info & MEMTYPE_MASK) { + case MEMTYPE_BYTE: + return 1; + case MEMTYPE_HWORD: + return 2; + case MEMTYPE_WORD: + case MEMTYPE_FLOAT: + return 4; + case MEMTYPE_VQUAD: + return 16; + } + + return 0; } const char *MIPSDisasmAt(u32 compilerPC) { diff --git a/Core/MIPS/MIPSTables.h b/Core/MIPS/MIPSTables.h index fd12c43a96..484eab35ea 100644 --- a/Core/MIPS/MIPSTables.h +++ b/Core/MIPS/MIPSTables.h @@ -130,5 +130,6 @@ int MIPSInterpret_RunUntil(u64 globalTicks); MIPSInterpretFunc MIPSGetInterpretFunc(MIPSOpcode op); int MIPSGetInstructionCycleEstimate(MIPSOpcode op); +int MIPSGetMemoryAccessSize(MIPSOpcode op); const char *MIPSGetName(MIPSOpcode op); const char *MIPSDisasmAt(u32 compilerPC); diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index 0f1d6688ab..1019cbf494 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -343,6 +343,10 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) { } int GetVectorOverlap(int vec1, VectorSize size1, int vec2, VectorSize size2) { + // Different matrices? Can't overlap, return early. + if (((vec1 >> 2) & 7) != ((vec2 >> 2) & 7)) + return 0; + int n1 = GetNumVectorElements(size1); int n2 = GetNumVectorElements(size2); u8 regs1[4]; @@ -674,7 +678,7 @@ static int32_t get_sign(uint32_t x) { return x & 0x80000000; } -float vfpu_dot(float a[4], float b[4]) { +float vfpu_dot(const float a[4], const float b[4]) { static const int EXTRA_BITS = 2; float2int result; float2int src[2]; diff --git a/Core/MIPS/MIPSVFPUUtils.h b/Core/MIPS/MIPSVFPUUtils.h index df1a1b85b0..6506a0664d 100644 --- a/Core/MIPS/MIPSVFPUUtils.h +++ b/Core/MIPS/MIPSVFPUUtils.h @@ -63,7 +63,7 @@ inline float vfpu_clamp(float v, float min, float max) { return v >= max ? max : (v <= min ? min : v); } -float vfpu_dot(float a[4], float b[4]); +float vfpu_dot(const float a[4], const float b[4]); float vfpu_sqrt(float a); float vfpu_rsqrt(float a); diff --git a/Core/MIPS/fake/FakeJit.cpp b/Core/MIPS/fake/FakeJit.cpp index 8150e26118..d8fb86d07d 100644 --- a/Core/MIPS/fake/FakeJit.cpp +++ b/Core/MIPS/fake/FakeJit.cpp @@ -98,9 +98,10 @@ void FakeJit::ClearCache() //GenerateFixedCode(); } -void FakeJit::InvalidateCacheAt(u32 em_address, int length) -{ - blocks.InvalidateICache(em_address, length); +void FakeJit::InvalidateCacheAt(u32 em_address, int length) { + if (blocks.RangeMayHaveEmuHacks(em_address, em_address + length)) { + blocks.InvalidateICache(em_address, length); + } } void FakeJit::EatInstruction(MIPSOpcode op) { diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index fef6f0487c..471414e453 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -66,8 +66,8 @@ void ImHere() { } void Jit::GenerateFixedCode(JitOptions &jo) { + BeginWrite(GetMemoryProtectPageSize()); AlignCodePage(); - BeginWrite(); restoreRoundingMode = AlignCode16(); { STMXCSR(MIPSSTATE_VAR(temp)); diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index e3534b39fe..c8319efcb0 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -23,6 +23,7 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/x86/Jit.h" #include "Core/MIPS/x86/RegCache.h" diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 88aa7da0b9..5af118061e 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -220,7 +220,7 @@ void Jit::ApplyPrefixD(const u8 *vregs, VectorSize sz) { // Vector regs can overlap in all sorts of swizzled ways. // This does allow a single overlap in sregs[i]. -bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { +bool IsOverlapSafeAllowS(int dreg, int di, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = NULL) { for (int i = 0; i < sn; ++i) { if (sregs[i] == dreg && i != di) return false; @@ -234,7 +234,7 @@ bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tr return true; } -bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) { +bool IsOverlapSafe(int dreg, int di, int sn, const u8 sregs[], int tn = 0, const u8 tregs[] = NULL) { return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg; } @@ -1605,13 +1605,25 @@ void Jit::Comp_Vh2f(MIPSOpcode op) { #define SSE_CONST4(name, val) alignas(16) static const u32 name[4] = { (val), (val), (val), (val) } SSE_CONST4(mask_nosign, 0x7fff); + SSE_CONST4(nan_mantissa, 0x800003ff); SSE_CONST4(magic, (254 - 15) << 23); SSE_CONST4(was_infnan, 0x7bff); SSE_CONST4(exp_infnan, 255 << 23); - // TODO: Fix properly - if (!RipAccessible(mask_nosign)) { - DISABLE; + OpArg mask_nosign_arg, nan_mantissa_arg, magic_arg, was_infnan_arg, exp_infnan_arg; + if (RipAccessible(mask_nosign)) { + mask_nosign_arg = M(&mask_nosign[0]); + nan_mantissa_arg = M(&nan_mantissa[0]); + magic_arg = M(&magic[0]); + was_infnan_arg = M(&was_infnan[0]); + exp_infnan_arg = M(&exp_infnan[0]); + } else { + MOV(PTRBITS, R(TEMPREG), ImmPtr(&mask_nosign[0])); + mask_nosign_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &mask_nosign[0]); + nan_mantissa_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &nan_mantissa[0]); + magic_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &magic[0]); + was_infnan_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &was_infnan[0]); + exp_infnan_arg = MAccessibleDisp(TEMPREG, &mask_nosign[0], &exp_infnan[0]); } #undef SSE_CONST4 @@ -1649,30 +1661,36 @@ void Jit::Comp_Vh2f(MIPSOpcode op) { // OK, 16 bits in each word. // Let's go. Deep magic here. MOVAPS(XMM1, R(XMM0)); - ANDPS(XMM0, M(&mask_nosign[0])); // xmm0 = expmant. not rip accessible but bailing above + ANDPS(XMM0, mask_nosign_arg); // xmm0 = expmant XORPS(XMM1, R(XMM0)); // xmm1 = justsign = expmant ^ xmm0 MOVAPS(tempR, R(XMM0)); - PCMPGTD(tempR, M(&was_infnan[0])); // xmm2 = b_wasinfnan. not rip accessible but bailing above PSLLD(XMM0, 13); - MULPS(XMM0, M(magic)); /// xmm0 = scaled + MULPS(XMM0, magic_arg); /// xmm0 = scaled PSLLD(XMM1, 16); // xmm1 = sign - ANDPS(tempR, M(&exp_infnan[0])); // not rip accessible but bailing above - ORPS(XMM1, R(tempR)); ORPS(XMM0, R(XMM1)); + // Now create a NAN mask, adding in the sign. + ORPS(XMM1, R(tempR)); // xmm1 = sign + original mantissa. + ANDPS(XMM1, nan_mantissa_arg); // xmm1 = original mantissa + PCMPGTD(tempR, was_infnan_arg); // xmm2 = b_wasinfnan + ORPS(XMM1, exp_infnan_arg); // xmm1 = infnan result + ANDPS(XMM1, R(tempR)); // xmm1 = infnan result OR zero if not infnan + ANDNPS(tempR, R(XMM0)); // tempR = result OR zero if infnan + ORPS(XMM1, R(tempR)); + fpr.MapRegsV(dregs, outsize, MAP_NOINIT | MAP_DIRTY); // TODO: Could apply D-prefix in parallel here... - MOVSS(fpr.V(dregs[0]), XMM0); - SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(3, 3, 2, 1)); - MOVSS(fpr.V(dregs[1]), XMM0); + MOVSS(fpr.V(dregs[0]), XMM1); + SHUFPS(XMM1, R(XMM1), _MM_SHUFFLE(3, 3, 2, 1)); + MOVSS(fpr.V(dregs[1]), XMM1); if (sz != V_Single) { - SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(3, 3, 2, 1)); - MOVSS(fpr.V(dregs[2]), XMM0); - SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(3, 3, 2, 1)); - MOVSS(fpr.V(dregs[3]), XMM0); + SHUFPS(XMM1, R(XMM1), _MM_SHUFFLE(3, 3, 2, 1)); + MOVSS(fpr.V(dregs[2]), XMM1); + SHUFPS(XMM1, R(XMM1), _MM_SHUFFLE(3, 3, 2, 1)); + MOVSS(fpr.V(dregs[3]), XMM1); } ApplyPrefixD(dregs, outsize); diff --git a/Core/MIPS/x86/IRToX86.h b/Core/MIPS/x86/IRToX86.h index d1555f6405..31a2cc3297 100644 --- a/Core/MIPS/x86/IRToX86.h +++ b/Core/MIPS/x86/IRToX86.h @@ -14,7 +14,7 @@ public: class IRToX86 : public IRToNativeInterface { public: void SetCodeBlock(Gen::XCodeBlock *code) { code_ = code; } - virtual void ConvertIRToNative(const IRInst *instructions, int count, const u32 *constants) override; + void ConvertIRToNative(const IRInst *instructions, int count, const u32 *constants) override; private: Gen::XCodeBlock *code_; diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index c27ee3b502..ec74bcfb5d 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -34,6 +34,7 @@ #include "Core/Reporting.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSInt.h" #include "Core/MIPS/MIPSTables.h" @@ -280,7 +281,8 @@ void Jit::Compile(u32 em_address) { return; } - BeginWrite(); + // Sometimes we compile fairly large blocks, although it's uncommon. + BeginWrite(JitBlockCache::MAX_BLOCK_INSTRUCTIONS * 16); int block_num = blocks.AllocateBlock(em_address); JitBlock *b = blocks.GetBlock(block_num); @@ -590,7 +592,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) { // Not sure about the cause. Memory::Opcode origInstruction = Memory::Read_Instruction(GetCompilerPC(), true); if (origInstruction.encoding == op.encoding) { - ERROR_LOG(HLE, "Replacement broken (savestate problem?): %08x", op.encoding); + ERROR_LOG(HLE, "Replacement broken (savestate problem?): %08x at %08x", op.encoding, GetCompilerPC()); return; } diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 0c96188ee4..8427f837ec 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -44,7 +44,7 @@ struct RegCacheState { class Jit : public Gen::XCodeBlock, public JitInterface, public MIPSFrontendInterface { public: Jit(MIPSState *mipsState); - virtual ~Jit(); + ~Jit(); const JitOptions &GetJitOptions() { return jo; } diff --git a/Core/MIPS/x86/JitSafeMem.cpp b/Core/MIPS/x86/JitSafeMem.cpp index 38c6c75554..8a6e8a6788 100644 --- a/Core/MIPS/x86/JitSafeMem.cpp +++ b/Core/MIPS/x86/JitSafeMem.cpp @@ -23,6 +23,7 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/MemMap.h" #include "Core/MIPS/JitCommon/JitCommon.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/x86/Jit.h" #include "Core/MIPS/x86/JitSafeMem.h" #include "Core/System.h" @@ -461,7 +462,7 @@ void JitSafeMemFuncs::Init(ThunkManager *thunks) { AllocCodeSpace(FUNCS_ARENA_SIZE); thunks_ = thunks; - BeginWrite(); + BeginWrite(1024); readU32 = GetCodePtr(); CreateReadFunc(32, (const void *)&Memory::Read_U32); readU16 = GetCodePtr(); diff --git a/Core/MIPS/x86/RegCache.h b/Core/MIPS/x86/RegCache.h index 218677485d..f852401f8d 100644 --- a/Core/MIPS/x86/RegCache.h +++ b/Core/MIPS/x86/RegCache.h @@ -20,7 +20,6 @@ #include "ppsspp_config.h" #include "Common/x64Emitter.h" #include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" namespace X64JitConstants { #if PPSSPP_ARCH(AMD64) @@ -42,6 +41,10 @@ namespace X64JitConstants { #endif } +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct MIPSCachedReg { Gen::OpArg location; bool away; // value not in source register diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index 04faf64cdd..0e63de5a68 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -19,7 +19,6 @@ #include "Common/x64Emitter.h" #include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSVFPUUtils.h" #undef MAP_NOINIT @@ -56,6 +55,10 @@ enum { #define NUM_X_FPREGS 8 #endif +namespace MIPSAnalyst { +struct AnalysisResults; +}; + struct X64CachedFPReg { union { int mipsReg; diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 52ef9ff5f9..50a2d564fa 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -335,6 +335,8 @@ static void DoMemoryVoid(PointerWrap &p, uint32_t start, uint32_t size) { _dbg_assert_msg_(d[i] == storage[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", d[i], d[i], &d[i], storage[i], storage[i], &storage[i]); }, 0, size, 128); break; + case PointerWrap::MODE_NOOP: + break; } storage += size; } diff --git a/Core/MemMapHelpers.h b/Core/MemMapHelpers.h index fdee215d03..56a950728c 100644 --- a/Core/MemMapHelpers.h +++ b/Core/MemMapHelpers.h @@ -71,9 +71,8 @@ inline void Memcpy(const u32 to_address, const u32 from_address, const u32 len, if (MemBlockInfoDetailed(len)) { char tagData[128]; if (!tag) { - const std::string srcTag = GetMemWriteTagAt("Memcpy/", from_address, len); + tagLen = FormatMemWriteTagAt(tagData, sizeof(tagData), "Memcpy/", from_address, len); tag = tagData; - tagLen = truncate_cpy(tagData, srcTag.c_str()); } NotifyMemInfo(MemBlockFlags::READ, from_address, len, tag, tagLen); NotifyMemInfo(MemBlockFlags::WRITE, to_address, len, tag, tagLen); diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index bf9f3070ca..148e4307d1 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -316,7 +316,11 @@ namespace SaveState } else { Memory::DoState(p); } - RestoreSavedReplacements(savedReplacements); + + // Don't bother restoring if reading, we'll deal with that in KernelModuleDoState. + // In theory, different functions might have been runtime loaded in the state. + if (p.mode != p.MODE_READ) + RestoreSavedReplacements(savedReplacements); MemoryStick_DoState(p); currentMIPS->DoState(p); diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index 00f7d0a305..6ad9de9316 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -41,7 +41,7 @@ public: JPEGFileStream(const Path &filename) { fp_ = File::OpenCFile(filename, "wb"); } - ~JPEGFileStream() override { + ~JPEGFileStream() { if (fp_ ) { fclose(fp_); } diff --git a/Core/System.cpp b/Core/System.cpp index cb6fc34fa8..35da73d353 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -599,7 +599,6 @@ void PSP_RunLoopUntil(u64 globalticks) { } mipsr4k.RunLoopUntil(globalticks); - gpu->CleanupBeforeUI(); } void PSP_RunLoopFor(int cycles) { diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index fb6b436661..dcd413ff2b 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -21,6 +21,11 @@ #include #include #include +#ifdef SHARED_LIBZIP +#include +#else +#include "ext/libzip/zip.h" +#endif #include "ext/xxhash.h" @@ -44,9 +49,11 @@ #include "GPU/Common/TextureDecoder.h" static const std::string INI_FILENAME = "textures.ini"; +static const std::string ZIP_FILENAME = "textures.zip"; static const std::string NEW_TEXTURE_DIR = "new/"; static const int VERSION = 1; static const int MAX_MIP_LEVELS = 12; // 12 should be plenty, 8 is the max mip levels supported by the PSP. +static const double MAX_CACHE_SIZE = 4.0; TextureReplacer::TextureReplacer() { none_.initDone_ = true; @@ -54,6 +61,8 @@ TextureReplacer::TextureReplacer() { } TextureReplacer::~TextureReplacer() { + if (zip_) + zip_close(zip_); } void TextureReplacer::Init() { @@ -76,8 +85,11 @@ void TextureReplacer::NotifyConfigChanged() { File::CreateEmptyFile(newTextureDir / ".nomedia"); } - enabled_ = File::Exists(basePath_) && File::IsDirectory(basePath_); + enabled_ = File::IsDirectory(basePath_); } else if (wasEnabled) { + if (zip_) + zip_close(zip_); + zip_ = nullptr; Decimate(ReplacerDecimateMode::ALL); } @@ -86,6 +98,44 @@ void TextureReplacer::NotifyConfigChanged() { } } +static struct zip *ZipOpenPath(Path fileName) { + int error = 0; + if (fileName.Type() == PathType::CONTENT_URI) { + int fd = File::OpenFD(fileName, File::OPEN_READ); + return zip_fdopen(fd, 0, &error); + } + return zip_open(fileName.c_str(), 0, &error); +} + +static constexpr zip_uint64_t INVALID_ZIP_SIZE = 0xFFFFFFFFFFFFFFFFULL; +static zip_uint64_t ZipFileSize(zip *z, zip_int64_t i) { + zip_stat_t zstat; + if (zip_stat_index(z, i, 0, &zstat) != 0) + return INVALID_ZIP_SIZE; + if ((zstat.valid & ZIP_STAT_SIZE) == 0) + return INVALID_ZIP_SIZE; + return zstat.size; +} + +static bool LoadIniZip(IniFile &ini, zip *z, const std::string &filename) { + zip_int64_t i = zip_name_locate(z, filename.c_str(), ZIP_FL_NOCASE); + if (i < 0) + return false; + + std::string inistr; + zip_uint64_t sz = ZipFileSize(z, i); + if (sz == INVALID_ZIP_SIZE) + return false; + inistr.resize(sz); + + zip_file_t *zf = zip_fopen_index(z, i, 0); + inistr.resize(zip_fread(zf, &inistr[0], inistr.size())); + zip_fclose(zf); + + std::stringstream sstream(inistr); + return ini.Load(sstream); +} + bool TextureReplacer::LoadIni() { // TODO: Use crc32c? hash_ = ReplacedTextureHash::QUICK; @@ -101,10 +151,32 @@ bool TextureReplacer::LoadIni() { // Prevents dumping the mipmaps. ignoreMipmap_ = false; - if (File::Exists(basePath_ / INI_FILENAME)) { - IniFile ini; - ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString()); + if (zip_) + zip_close(zip_); + zip_ = nullptr; + IniFile ini; + bool iniLoaded = false; + + // First, check for textures.zip, which is used to reduce IO. + zip *z = ZipOpenPath(basePath_ / ZIP_FILENAME); + if (z) { + iniLoaded = LoadIniZip(ini, z, INI_FILENAME); + // Require the zip have textures.ini to use it. + if (iniLoaded) { + iniLoaded = true; + zip_ = z; + } else { + zip_close(z); + z = nullptr; + } + } + + if (!iniLoaded) { + iniLoaded = ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString()); + } + + if (iniLoaded) { if (!LoadIniValues(ini)) { return false; } @@ -113,10 +185,17 @@ bool TextureReplacer::LoadIni() { std::string overrideFilename; if (ini.GetOrCreateSection("games")->Get(gameID_.c_str(), &overrideFilename, "")) { if (!overrideFilename.empty() && overrideFilename != INI_FILENAME) { - INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str()); IniFile overrideIni; - overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString()); + if (zip_) + iniLoaded = LoadIniZip(overrideIni, zip_, overrideFilename); + else + iniLoaded = overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString()); + if (!iniLoaded) { + ERROR_LOG(G3D, "Failed to load extra texture ini: %s", overrideFilename.c_str()); + return false; + } + INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str()); if (!LoadIniValues(overrideIni, true)) { return false; } @@ -410,7 +489,7 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, for (int i = 0; i < MAX_MIP_LEVELS; ++i) { const std::string hashfile = LookupHashFile(cachekey, hash, i); const Path filename = basePath_ / hashfile; - if (hashfile.empty() || !File::Exists(filename)) { + if (hashfile.empty()) { // Out of valid mip levels. Bail out. break; } @@ -418,7 +497,16 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, ReplacedTextureLevel level; level.fmt = Draw::DataFormat::R8G8B8A8_UNORM; level.file = filename; - bool good = PopulateLevel(level); + + bool good; + bool logError = hashfile != HashName(cachekey, hash, i) + ".png"; + if (zip_) { + level.z = zip_; + level.zi = zip_name_locate(zip_, hashfile.c_str(), ZIP_FL_NOCASE); + good = PopulateLevelFromZip(level, !logError); + } else { + good = PopulateLevelFromPath(level, !logError); + } // We pad files that have been hashrange'd so they are the same texture size. level.w = (level.w * w) / newW; @@ -439,6 +527,12 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, break; } + // Populate the level data pointers for each level. + result->levelData_.resize(result->levels_.size()); + for (size_t i = 0; i < result->levels_.size(); ++i) { + result->levelData_[i] = &levelCache_[result->levels_[i]]; + } + result->prepareDone_ = true; } @@ -448,12 +542,7 @@ enum class ReplacedImageType { INVALID, }; -static ReplacedImageType Identify(FILE *fp) { - uint8_t magic[4]; - if (fread(magic, 1, 4, fp) != 4) - return ReplacedImageType::INVALID; - rewind(fp); - +static ReplacedImageType Identify(const uint8_t magic[4]) { if (strncmp((const char *)magic, "ZIMG", 4) == 0) return ReplacedImageType::ZIM; if (magic[0] == 0x89 && strncmp((const char *)&magic[1], "PNG", 3) == 0) @@ -461,12 +550,30 @@ static ReplacedImageType Identify(FILE *fp) { return ReplacedImageType::INVALID; } -bool TextureReplacer::PopulateLevel(ReplacedTextureLevel &level) { +static ReplacedImageType Identify(FILE *fp) { + uint8_t magic[4]; + if (fread(magic, 1, 4, fp) != 4) + return ReplacedImageType::INVALID; + rewind(fp); + + return Identify(magic); +} + +static ReplacedImageType Identify(zip_file_t *zf) { + uint8_t magic[4]; + if (zip_fread(zf, magic, 4) != 4) + return ReplacedImageType::INVALID; + + return Identify(magic); +} + +bool TextureReplacer::PopulateLevelFromPath(ReplacedTextureLevel &level, bool ignoreError) { bool good = false; FILE *fp = File::OpenCFile(level.file, "rb"); if (!fp) { - ERROR_LOG(G3D, "Error opening replacement texture file '%s'", level.file.c_str()); + if (!ignoreError) + ERROR_LOG(G3D, "Error opening replacement texture file '%s'", level.file.c_str()); return false; } @@ -499,6 +606,62 @@ bool TextureReplacer::PopulateLevel(ReplacedTextureLevel &level) { return good; } +bool TextureReplacer::PopulateLevelFromZip(ReplacedTextureLevel &level, bool ignoreError) { + bool good = false; + + if (!level.z || level.zi < 0) { + if (!ignoreError) + ERROR_LOG(G3D, "Error opening replacement texture file '%s' in textures.zip", level.file.c_str()); + return false; + } + + zip_file_t *zf = zip_fopen_index(level.z, level.zi, 0); + if (!zf) + return false; + + auto imageType = Identify(zf); + zip_fclose(zf); + + zf = zip_fopen_index(level.z, level.zi, 0); + if (imageType == ReplacedImageType::ZIM) { + uint32_t ignore = 0; + good = zip_fread(zf, &ignore, 4) == 4; + good = good && zip_fread(zf, &level.w, 4) == 4; + good = good && zip_fread(zf, &level.h, 4) == 4; + int flags; + if (good && zip_fread(zf, &flags, 4) == 4) { + good = (flags & ZIM_FORMAT_MASK) == ZIM_RGBA8888; + } + } else if (imageType == ReplacedImageType::PNG) { + png_image png = {}; + png.version = PNG_IMAGE_VERSION; + + // TODO: Use some way to stream data into libpng. Better than the IO lookups on Android... + zip_uint64_t zsize = ZipFileSize(level.z, level.zi); + std::string pngdata; + if (zsize != INVALID_ZIP_SIZE) + pngdata.resize(zsize); + if (!pngdata.empty()) { + pngdata.resize(zip_fread(zf, &pngdata[0], pngdata.size())); + } + + if (png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) { + // We pad files that have been hashrange'd so they are the same texture size. + level.w = png.width; + level.h = png.height; + good = true; + } else { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", level.file.ToVisualString().c_str(), png.message); + } + png_image_free(&png); + } else { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - unsupported format (zip)", level.file.ToVisualString().c_str()); + } + zip_fclose(zf); + + return good; +} + static bool WriteTextureToPNG(png_imagep image, const Path &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { FILE *fp = File::OpenCFile(filename, "wb"); if (!fp) { @@ -673,15 +836,32 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl void TextureReplacer::Decimate(ReplacerDecimateMode mode) { // Allow replacements to be cached for a long time, although they're large. double age = 1800.0; - if (mode == ReplacerDecimateMode::FORCE_PRESSURE) + if (mode == ReplacerDecimateMode::FORCE_PRESSURE) { age = 90.0; - else if (mode == ReplacerDecimateMode::ALL) + } else if (mode == ReplacerDecimateMode::ALL) { age = 0.0; + } else if (lastTextureCacheSizeGB_ > 1.0) { + double pressure = std::min(MAX_CACHE_SIZE, lastTextureCacheSizeGB_) / MAX_CACHE_SIZE; + // Get more aggressive the closer we are to the max. + age = 90.0 + (1.0 - pressure) * 1710.0; + } const double threshold = time_now_d() - age; for (auto &item : cache_) { item.second.PurgeIfOlder(threshold); } + + size_t totalSize = 0; + for (auto &item : levelCache_) { + std::lock_guard guard(item.second.lock); + totalSize += item.second.data.size(); + } + + double totalSizeGB = totalSize / (1024.0 * 1024.0 * 1024.0); + if (totalSizeGB >= 1.0) { + WARN_LOG(G3D, "Decimated replacements older than %fs, currently using %f GB of RAM", age, totalSizeGB); + } + lastTextureCacheSizeGB_ = totalSizeGB; } template @@ -821,8 +1001,11 @@ bool ReplacedTexture::IsReady(double budget) { } // Loaded already, or not yet on a thread? - if (initDone_ && !levelData_.empty()) + if (initDone_ && !levelData_.empty()) { + for (auto &l : levelData_) + l->lastUsed = lastUsed_; return true; + } // Let's not even start a new texture if we're already behind. if (budget < 0.0) return false; @@ -856,7 +1039,6 @@ void ReplacedTexture::Prepare() { return; } - levelData_.resize(levels_.size()); for (int i = 0; i < (int)levels_.size(); ++i) { if (cancelPrepare_) break; @@ -870,39 +1052,87 @@ void ReplacedTexture::Prepare() { void ReplacedTexture::PrepareData(int level) { _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel"); + _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel"); + + // We must lock around access to levelData_ in case two textures try to load it at once. + std::lock_guard guard(levelData_[level]->lock); const ReplacedTextureLevel &info = levels_[level]; - std::vector &out = levelData_[level]; + std::vector &out = levelData_[level]->data; - FILE *fp = File::OpenCFile(info.file, "rb"); - if (!fp) { - // Leaving the data sized at zero means failure. + // Already populated from cache. + if (!out.empty()) return; - } - auto imageType = Identify(fp); - if (imageType == ReplacedImageType::ZIM) { - size_t zimSize = File::GetFileSize(fp); - std::unique_ptr zim(new uint8_t[zimSize]); - if (!zim) { - ERROR_LOG(G3D, "Failed to allocate memory for texture replacement"); - fclose(fp); + FILE *fp = nullptr; + zip_file_t *zf = nullptr; + ReplacedImageType imageType; + if (info.z) { + zf = zip_fopen_index(info.z, info.zi, 0); + if (!zf) + return; + + imageType = Identify(zf); + // Can't assume we can seek. Reopen. + zip_fclose(zf); + zf = zip_fopen_index(info.z, info.zi, 0); + } else { + fp = File::OpenCFile(info.file, "rb"); + if (!fp) { + // Leaving the data sized at zero means failure. return; } - if (fread(&zim[0], 1, zimSize, fp) != zimSize) { - ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", info.file.c_str()); + imageType = Identify(fp); + } + + auto cleanup = [&] { + if (zf) + zip_fclose(zf); + if (fp) fclose(fp); + }; + + if (imageType == ReplacedImageType::ZIM) { + size_t zimSize; + if (fp) { + zimSize = File::GetFileSize(fp); + } else if (zf) { + zip_uint64_t zsize = ZipFileSize(info.z, info.zi); + zimSize = zsize == INVALID_ZIP_SIZE ? 0 : (size_t)zsize; + } else { + _assert_(false); + } + std::unique_ptr zim(new uint8_t[zimSize]); + if (!zim) { + ERROR_LOG(G3D, "Failed to allocate memory for texture replacement"); + cleanup(); return; } + if (fp) { + if (fread(&zim[0], 1, zimSize, fp) != zimSize) { + ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", info.file.c_str()); + cleanup(); + return; + } + } else if (zf) { + if (zip_fread(zf, &zim[0], zimSize) != zimSize) { + ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM (zip)", info.file.c_str()); + cleanup(); + return; + } + } else { + _assert_(false); + } + int w, h, f; uint8_t *image; if (LoadZIMPtr(&zim[0], zimSize, &w, &h, &f, &image)) { if (w > info.w || h > info.h) { ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str()); - fclose(fp); + cleanup(); return; } @@ -925,14 +1155,33 @@ void ReplacedTexture::PrepareData(int level) { png_image png = {}; png.version = PNG_IMAGE_VERSION; - if (!png_image_begin_read_from_stdio(&png, fp)) { - ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s", info.file.c_str(), png.message); - fclose(fp); - return; + // Needs to survive for a little while, used for zip only. + std::string pngdata; + if (fp) { + if (!png_image_begin_read_from_stdio(&png, fp)) { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s", info.file.c_str(), png.message); + cleanup(); + return; + } + } else if (zf) { + zip_uint64_t zsize = ZipFileSize(info.z, info.zi); + if (zsize != INVALID_ZIP_SIZE) + pngdata.resize(zsize); + if (!pngdata.empty()) { + pngdata.resize(zip_fread(zf, &pngdata[0], pngdata.size())); + } + + if (!png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) { + ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", info.file.c_str(), png.message); + cleanup(); + return; + } + } else { + _assert_(false); } if (png.width > (uint32_t)info.w || png.height > (uint32_t)info.h) { ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str()); - fclose(fp); + cleanup(); return; } @@ -949,7 +1198,7 @@ void ReplacedTexture::PrepareData(int level) { out.resize(info.w * info.h * 4); if (!png_image_finish_read(&png, nullptr, &out[0], info.w * 4, nullptr)) { ERROR_LOG(G3D, "Could not load texture replacement: %s - %s", info.file.c_str(), png.message); - fclose(fp); + cleanup(); out.resize(0); return; } @@ -964,13 +1213,23 @@ void ReplacedTexture::PrepareData(int level) { } } - fclose(fp); + cleanup(); } void ReplacedTexture::PurgeIfOlder(double t) { - if (lastUsed_ < t && (!threadWaitable_ || threadWaitable_->WaitFor(0.0))) { - levelData_.clear(); - initDone_ = false; + if (threadWaitable_ && !threadWaitable_->WaitFor(0.0)) + return; + if (lastUsed_ >= t) + return; + + for (auto &l : levelData_) { + if (l->lastUsed < t) { + // We have to lock since multiple textures might reference this same data. + std::lock_guard guard(l->lock); + l->data.clear(); + // This means we have to reload. If we never purge any, there's no need. + initDone_ = false; + } } } @@ -993,8 +1252,13 @@ bool ReplacedTexture::Load(int level, void *out, int rowPitch) { if (levelData_.empty()) return false; + _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel"); + + // We probably could avoid this lock, but better to play it safe. + std::lock_guard guard(levelData_[level]->lock); + const ReplacedTextureLevel &info = levels_[level]; - const std::vector &data = levelData_[level]; + const std::vector &data = levelData_[level]->data; if (data.empty()) return false; diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index b32d31a7d3..4fb5bf5224 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -17,11 +17,13 @@ #pragma once +#include "ppsspp_config.h" #include #include #include #include +#include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/MemoryUtil.h" #include "Common/File/Path.h" @@ -35,6 +37,7 @@ class TextureCacheCommon; class TextureReplacer; class ReplacedTextureTask; class LimitedWaitable; +struct zip; // These must match the constants in TextureCacheCommon. enum class ReplacedTextureAlpha { @@ -54,6 +57,38 @@ struct ReplacedTextureLevel { int h; Draw::DataFormat fmt; // NOTE: Right now, the only supported format is Draw::DataFormat::R8G8B8A8_UNORM. Path file; + // Can be ignored for hashing/equal, since file has all uniqueness. + // To be able to reload, we need to be able to reopen, unfortunate we can't use zip_file_t. + zip *z = nullptr; + int64_t zi = -1; + + bool operator ==(const ReplacedTextureLevel &other) const { + if (w != other.w || h != other.h || fmt != other.fmt) + return false; + return file == other.file; + } +}; + +namespace std { + template <> + struct hash { + std::size_t operator()(const ReplacedTextureLevel &k) const { +#if PPSSPP_ARCH(64BIT) + uint64_t v = (uint64_t)k.w | ((uint64_t)k.h << 32); + v = __rotl64(v ^ (uint64_t)k.fmt, 13); +#else + uint32_t v = k.w ^ (uint32_t)k.fmt; + v = __rotl(__rotl(v, 13) ^ k.h, 13); +#endif + return v ^ hash()(k.file.ToString()); + } + }; +} + +struct ReplacedLevelCache { + std::mutex lock; + std::vector data; + double lastUsed = 0.0; }; struct ReplacementCacheKey { @@ -169,7 +204,7 @@ protected: void PurgeIfOlder(double t); std::vector levels_; - std::vector> levelData_; + std::vector levelData_; ReplacedTextureAlpha alphaStatus_ = ReplacedTextureAlpha::UNKNOWN; double lastUsed_ = 0.0; LimitedWaitable *threadWaitable_ = nullptr; @@ -240,7 +275,8 @@ protected: std::string LookupHashFile(u64 cachekey, u32 hash, int level); std::string HashName(u64 cachekey, u32 hash, int level); void PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h); - bool PopulateLevel(ReplacedTextureLevel &level); + bool PopulateLevelFromPath(ReplacedTextureLevel &level, bool ignoreError); + bool PopulateLevelFromZip(ReplacedTextureLevel &level, bool ignoreError); bool enabled_ = false; bool allowVideo_ = false; @@ -248,10 +284,13 @@ protected: bool reduceHash_ = false; float reduceHashSize = 1.0; // default value with reduceHash to false float reduceHashGlobalValue = 0.5; // Global value for textures dump pngs of all sizes, 0.5 by default but can be set in textures.ini + double lastTextureCacheSizeGB_ = 0.0; bool ignoreMipmap_ = false; std::string gameID_; Path basePath_; ReplacedTextureHash hash_ = ReplacedTextureHash::QUICK; + zip *zip_ = nullptr; + typedef std::pair WidthHeightPair; std::unordered_map hashranges_; std::unordered_map reducehashranges_; @@ -261,4 +300,5 @@ protected: ReplacedTexture none_; std::unordered_map cache_; std::unordered_map> savedCache_; + std::unordered_map levelCache_; }; diff --git a/Core/ThreadEventQueue.h b/Core/ThreadEventQueue.h index d365454776..161e06753c 100644 --- a/Core/ThreadEventQueue.h +++ b/Core/ThreadEventQueue.h @@ -28,6 +28,8 @@ template next) ++count; Do(p, count); diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index eac1edaed5..050589f2f0 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -421,14 +421,14 @@ static void DataProcessingRegister(uint32_t w, uint64_t addr, Instruction *instr const char *op = opcode2 >= 8 ? "unk" : opname[opcode]; snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d", op, r, Rd, r, Rn); } else if (((w >> 21) & 0x2FF) == 0x0D6) { - const char *opname[32] = { + const char *opname[64] = { 0, 0, "udiv", "sdiv", 0, 0, 0, 0, "lslv", "lsrv", "asrv", "rorv", 0, 0, 0, 0, "crc32b", "crc32h", "crc32w", 0, "crc32cb", "crc32ch", "crc32cw", 0, }; int opcode = (w >> 10) & 0x3F; // Data processing (2 source) - snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opname[opcode], r, Rd, r, Rn, r, Rm); + snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opname[opcode] ? opname[opcode] : "?", r, Rd, r, Rn, r, Rm); } else if (((w >> 24) & 0x1f) == 0xA) { // Logical (shifted register) int shift = (w >> 22) & 0x3; @@ -929,9 +929,9 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) { snprintf(instr->text, sizeof(instr->text), "(float cond compare %08x)", w); } else if (((w >> 10) & 3) == 2) { int opc = (w >> 12) & 0xf; - const char *opnames[9] = { "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul" }; + const char *opnames[16] = { "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul" }; char r = ((w >> 22) & 1) ? 'd' : 's'; - snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opnames[opc], r, Rd, r, Rn, r, Rm); + snprintf(instr->text, sizeof(instr->text), "%s %c%d, %c%d, %c%d", opnames[opc] ? opnames[opc] : "?", r, Rd, r, Rn, r, Rm); } else if (((w >> 10) & 3) == 3) { char fr = ((w >> 22) & 1) ? 'd' : 's'; int cond = (w >> 12) & 0xf; diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index e808f07b6c..7ae0bdb5ef 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -325,6 +325,9 @@ bool GameManager::InstallGame(Path url, Path fileName, bool deleteAfter) { if (DetectTexturePackDest(z, info.textureIniIndex, dest)) { INFO_LOG(HLE, "Installing '%s' into '%s'", fileName.c_str(), dest.c_str()); File::CreateFullPath(dest); + // Install as a zip file if textures.ini is in the root. Performs better on Android. + if (info.stripChars == 0) + return InstallMemstickZip(z, fileName, dest / "textures.zip", info, deleteAfter); File::CreateEmptyFile(dest / ".nomedia"); return InstallMemstickGame(z, fileName, dest, info, true, deleteAfter); } else { @@ -617,6 +620,60 @@ bail: return false; } +bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const Path &dest, const ZipFileInfo &info, bool deleteAfter) { + size_t allBytes = 0; + size_t bytesCopied = 0; + + auto sy = GetI18NCategory("System"); + + // We don't need the zip anymore, as we're going to copy it as-is. + zip_close(z); + z = nullptr; + + // Not using File::Copy() so we can report progress. + FILE *inf = File::OpenCFile(zipfile, "rb"); + if (!inf) + return false; + + allBytes = (size_t)File::GetFileSize(inf); + FILE *outf = File::OpenCFile(dest, "wb"); + if (!outf) { + SetInstallError(sy->T("Storage full")); + fclose(inf); + return false; + } + + const size_t blockSize = 1024 * 128; + u8 *buffer = new u8[blockSize]; + while (bytesCopied < allBytes) { + size_t readSize = std::min(blockSize, allBytes - bytesCopied); + if (fread(buffer, readSize, 1, inf) != 1) + break; + if (fwrite(buffer, readSize, 1, outf) != 1) + break; + bytesCopied += readSize; + installProgress_ = (float)bytesCopied / (float)allBytes; + } + + delete[] buffer; + fclose(inf); + fclose(outf); + + if (bytesCopied < allBytes) { + File::Delete(dest); + SetInstallError(sy->T("Storage full")); + return false; + } + + installProgress_ = 1.0f; + if (deleteAfter) { + File::Delete(zipfile); + } + InstallDone(); + ResetInstallError(); + return true; +} + bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter) { // Let's place the output file in the currently selected Games directory. diff --git a/Core/Util/GameManager.h b/Core/Util/GameManager.h index df74af2fd7..f7fc8ff7b5 100644 --- a/Core/Util/GameManager.h +++ b/Core/Util/GameManager.h @@ -79,6 +79,7 @@ public: private: bool InstallGame(Path url, Path tempFileName, bool deleteAfter); bool InstallMemstickGame(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter); + bool InstallMemstickZip(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool deleteAfter); bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter); bool InstallRawISO(const Path &zipFile, const std::string &originalName, bool deleteAfter); void InstallDone(); diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index d7559c0fa1..9d0c6f832c 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -913,12 +913,20 @@ static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, const PP return; } + // Sometimes our texture can be larger than 512 wide, which means we need to tile it. int bufw = ((im.entry.bmWidth + 31) / 32) * 32; - int wp2 = GetPow2(im.entry.bmWidth); + int tile1bmWidth = std::min(512, im.entry.bmWidth); + int tile2bmWidth = tile1bmWidth == 512 ? im.entry.bmWidth - 512 : 0; + bool hasTile2 = tile2bmWidth != 0; + + // Now figure the tile shift value. + int tile1wp2 = GetPow2(tile1bmWidth); + int tile2wp2 = hasTile2 ? GetPow2(tile2bmWidth) : 0; int hp2 = GetPow2(im.entry.bmHeight); + WriteCmd(GE_CMD_TEXADDR0, im.ptr & 0xFFFFF0); WriteCmd(GE_CMD_TEXBUFWIDTH0, bufw | ((im.ptr & 0xFF000000) >> 8)); - WriteCmd(GE_CMD_TEXSIZE0, wp2 | (hp2 << 8)); + WriteCmd(GE_CMD_TEXSIZE0, tile1wp2 | (hp2 << 8)); WriteCmd(GE_CMD_TEXFLUSH, 0); float w = im.entry.width * style.scale; @@ -934,21 +942,62 @@ static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, const PP y -= h; BeginVertexData(); - float u1 = (float)im.entry.width / (1 << wp2); + float tile2x = 512 * style.scale; + float tile1w = hasTile2 ? 512.0f * style.scale : w; + float tile2w = hasTile2 ? w - tile1w : 0.0f; + float tile1u1 = hasTile2 ? 1.0f : (float)im.entry.width / (1 << tile1wp2); + float tile2u1 = hasTile2 ? (float)(im.entry.width - 512) / (1 << tile2wp2) : 0.0f; float v1 = (float)im.entry.height / (1 << hp2); if (style.hasShadow) { // Draw more shadows for a blurrier shadow. + u32 shadowColor = alphaMul(style.shadowColor, 0.35f); for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { if (dx == 0.0f && dy == 0.0f) continue; - Vertex(x + dx, y + dy, 0, 0, 1 << wp2, 1 << hp2, alphaMul(style.shadowColor, 0.35f)); - Vertex(x + dx + w, y + dy + h, u1, v1, 1 << wp2, 1 << hp2, alphaMul(style.shadowColor, 0.35f)); + + Vertex(x + dx, y + dy, 0, 0, 1 << tile1wp2, 1 << hp2, shadowColor); + Vertex(x + dx + tile1w, y + dy + h, tile1u1, v1, 1 << tile1wp2, 1 << hp2, shadowColor); } } + + // Did we need another tile? + if (hasTile2) { + // Flush to change to tile2. + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + BeginVertexData(); + WriteCmd(GE_CMD_TEXADDR0, (im.ptr & 0xFFFFF0) + 256); + WriteCmd(GE_CMD_TEXSIZE0, tile2wp2 | (hp2 << 8)); + + for (float dy = 0.0f; dy <= 2.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 1.0f; dx += 0.5f) { + if (dx == 0.0f && dy == 0.0f) + continue; + + Vertex(x + tile2x + dx, y + dy, 0, 0, 1 << tile2wp2, 1 << hp2, shadowColor); + Vertex(x + tile2x + dx + tile2w, y + dy + h, tile2u1, v1, 1 << tile2wp2, 1 << hp2, shadowColor); + } + } + + // Return to tile1 for the text. + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + BeginVertexData(); + WriteCmd(GE_CMD_TEXADDR0, im.ptr & 0xFFFFF0); + WriteCmd(GE_CMD_TEXSIZE0, tile1wp2 | (hp2 << 8)); + } + } + + Vertex(x, y, 0, 0, 1 << tile1wp2, 1 << hp2, style.color); + Vertex(x + tile1w, y + h, tile1u1, v1, 1 << tile1wp2, 1 << hp2, style.color); + if (hasTile2) { + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + BeginVertexData(); + WriteCmd(GE_CMD_TEXADDR0, (im.ptr & 0xFFFFF0) + 256); + WriteCmd(GE_CMD_TEXSIZE0, tile2wp2 | (hp2 << 8)); + + Vertex(x + tile2x, y, 0, 0, 1 << tile2wp2, 1 << hp2, style.color); + Vertex(x + tile2x + tile2w, y + h, tile2u1, v1, 1 << tile2wp2, 1 << hp2, style.color); } - Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, style.color); - Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, style.color); EndVertexDataAndDraw(GE_PRIM_RECTANGLES); PPGeSetDefaultTexture(); diff --git a/Core/Util/PortManager.cpp b/Core/Util/PortManager.cpp index 79120053c8..b0c2bfe487 100644 --- a/Core/Util/PortManager.cpp +++ b/Core/Util/PortManager.cpp @@ -127,7 +127,13 @@ bool PortManager::Initialize(const unsigned int timeout) { m_leaseDuration = "43200"; // 12 hours m_InitState = UPNP_INITSTATE_BUSY; urls = (UPNPUrls*)malloc(sizeof(struct UPNPUrls)); + if (!urls) + return false; datas = (IGDdatas*)malloc(sizeof(struct IGDdatas)); + if (!datas) { + free(urls); + return false; + } memset(urls, 0, sizeof(struct UPNPUrls)); memset(datas, 0, sizeof(struct IGDdatas)); diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 628efc787f..52c67152ef 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -35,8 +35,8 @@ static const InputDef vsInputs[2] = { // TODO: Deduplicate with TextureShaderCommon.cpp static const SamplerDef samplers[2] = { - { "tex" }, - { "pal" }, + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, + { 1, "pal" }, }; static const VaryingDef varyings[1] = { @@ -349,7 +349,7 @@ void GenerateDepalSmoothed(ShaderWriter &writer, const DepalConfig &config) { void GenerateDepalFs(ShaderWriter &writer, const DepalConfig &config) { writer.DeclareSamplers(samplers); writer.HighPrecisionFloat(); - writer.BeginFSMain(config.bufferFormat == GE_FORMAT_DEPTH16 ? g_draw2Duniforms : Slice::empty(), varyings, FSFLAG_NONE); + writer.BeginFSMain(config.bufferFormat == GE_FORMAT_DEPTH16 ? g_draw2Duniforms : Slice::empty(), varyings); if (config.smoothedDepal) { // Handles a limited set of cases, but doesn't need any integer math so we don't // need two variants. @@ -369,5 +369,5 @@ void GenerateDepalFs(ShaderWriter &writer, const DepalConfig &config) { _assert_msg_(false, "Shader language not supported for depal: %d", (int)writer.Lang().shaderLanguage); } } - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); } diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 05bead52e4..ddc752ae21 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -37,7 +37,7 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { "tex" }, + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, }; const UniformDef g_draw2Duniforms[2] = { @@ -59,9 +59,9 @@ const UniformBufferDesc draw2DUBDesc{ sizeof(Draw2DUB), { Draw2DPipelineInfo GenerateDraw2DCopyColorFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); + writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_copy_color", @@ -72,13 +72,13 @@ Draw2DPipelineInfo GenerateDraw2DCopyColorFs(ShaderWriter &writer) { Draw2DPipelineInfo GenerateDraw2DCopyColorRect2LinFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); - writer.BeginFSMain(g_draw2Duniforms, varyings, FSFLAG_NONE); + writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec2 tSize = texSize / scaleFactor;\n"); writer.C(" vec2 pixels = v_texcoord * tSize;\n"); writer.C(" float u = mod(pixels.x, tSize.x);\n"); writer.C(" float v = floor(pixels.x / tSize.x);\n"); writer.C(" vec4 outColor = ").SampleTexture2D("tex", "vec2(u, v) / tSize").C(";\n"); - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_copy_color_rect2lin", @@ -88,11 +88,12 @@ Draw2DPipelineInfo GenerateDraw2DCopyColorRect2LinFs(ShaderWriter &writer) { } Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_WRITEDEPTH); + writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); writer.C(" gl_FragDepth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n"); - writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_copy_depth", @@ -102,8 +103,9 @@ Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) { } Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_WRITEDEPTH); + writer.BeginFSMain(Slice::empty(), varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll // have to apply the scaling. @@ -111,7 +113,7 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { writer.C(" vec3 rgb = ").SampleTexture2D("tex", "v_texcoord.xy").C(".xyz;\n"); writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n"); writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.scale, factors.offset); - writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_565_to_depth", @@ -121,8 +123,9 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthFs(ShaderWriter &writer) { } Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { + writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH); writer.DeclareSamplers(samplers); - writer.BeginFSMain(g_draw2Duniforms, varyings, FSFLAG_WRITEDEPTH); + writer.BeginFSMain(g_draw2Duniforms, varyings); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); // Unlike when just copying a depth buffer, here we're generating new depth values so we'll // have to apply the scaling. @@ -136,7 +139,7 @@ Draw2DPipelineInfo GenerateDraw2D565ToDepthDeswizzleFs(ShaderWriter &writer) { writer.C(" vec3 rgb = ").SampleTexture2D("tex", "coord").C(".xyz;\n"); writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n"); writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.scale, factors.offset); - writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "draw2d_565_to_depth_deswizzle", @@ -179,6 +182,11 @@ void Draw2D::Ensure2DResources() { if (!draw2DVs_) { char *vsCode = new char[8192]; + ShaderWriterFlags flags = ShaderWriterFlags::NONE; + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + // Hm, we're compiling the vertex shader here, probably don't need this... + flags = ShaderWriterFlags::FS_AUTO_STEREO; + } ShaderWriter writer(vsCode, shaderLanguageDesc, ShaderStage::Vertex); GenerateDraw2DVS(writer); _assert_msg_(strlen(vsCode) < 8192, "Draw2D VS length error: %d", (int)strlen(vsCode)); @@ -217,7 +225,11 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::functionGetShaderLanguageDesc(); char *fsCode = new char[8192]; - ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment); + ShaderWriterFlags flags = ShaderWriterFlags::NONE; + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + flags = ShaderWriterFlags::FS_AUTO_STEREO; + } + ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment, Slice::empty(), flags); Draw2DPipelineInfo info = generate(writer); _assert_msg_(strlen(fsCode) < 8192, "Draw2D FS length error: %d", (int)strlen(fsCode)); @@ -291,7 +303,7 @@ void Draw2D::Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX DrawStrip2D(nullptr, vtx, 4, linear, pipeline, srcWidth, srcHeight, scaleFactor); } -void Draw2D::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW, float texH, int scaleFactor) { +void Draw2D::DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW, float texH, int scaleFactor) { using namespace Draw; _dbg_assert_(pipeline); @@ -312,12 +324,13 @@ void Draw2D::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCoun draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); if (tex) { + // This won't work since all the shaders above expect array textures on Vulkan. draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); } draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, linearFilter ? &draw2DSamplerLinear_ : &draw2DSamplerNearest_); draw_->DrawUP(verts, vertexCount); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE | DIRTY_VERTEXSHADER_STATE); } diff --git a/GPU/Common/Draw2D.h b/GPU/Common/Draw2D.h index bf156e6d39..4d7d728404 100644 --- a/GPU/Common/Draw2D.h +++ b/GPU/Common/Draw2D.h @@ -61,7 +61,7 @@ public: Draw2DPipeline *Create2DPipeline(std::function generate); - void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW = 0.0f, float texH = 0.0f, int scaleFactor = 0); + void DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW = 0.0f, float texH = 0.0f, int scaleFactor = 0); void Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2, float srcWidth, float srcHeight, float dstWidth, float dstHeight, bool linear, int scaleFactor); void Ensure2DResources(); diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index f884486c65..762acf0668 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -16,8 +16,10 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/Data/Convert/ColorConv.h" +#include "Common/Math/lin/matrix4x4.h" #include "Common/Profiler/Profiler.h" #include "Common/LogReporting.h" #include "Core/Config.h" @@ -50,8 +52,7 @@ DrawEngineCommon::~DrawEngineCommon() { } void DrawEngineCommon::Init() { - useHWTransform_ = g_Config.bHardwareTransform; - useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation); + NotifyConfigChanged(); } VertexDecoder *DrawEngineCommon::GetVertexDecoder(u32 vtype) { @@ -131,10 +132,10 @@ std::string DrawEngineCommon::DebugGetVertexLoaderString(std::string id, DebugSh struct Plane { float x, y, z, w; void Set(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } - float Test(float f[3]) const { return x * f[0] + y * f[1] + z * f[2] + w; } + float Test(const float f[3]) const { return x * f[0] + y * f[1] + z * f[2] + w; } }; -static void PlanesFromMatrix(float mtx[16], Plane planes[6]) { +static void PlanesFromMatrix(const float mtx[16], Plane planes[6]) { planes[0].Set(mtx[3]-mtx[0], mtx[7]-mtx[4], mtx[11]-mtx[8], mtx[15]-mtx[12]); // Right planes[1].Set(mtx[3]+mtx[0], mtx[7]+mtx[4], mtx[11]+mtx[8], mtx[15]+mtx[12]); // Left planes[2].Set(mtx[3]+mtx[1], mtx[7]+mtx[5], mtx[11]+mtx[9], mtx[15]+mtx[13]); // Bottom @@ -167,7 +168,7 @@ static Vec3f ScreenToDrawing(const Vec3f& coords) { return ret; } -void DrawEngineCommon::Resized() { +void DrawEngineCommon::NotifyConfigChanged() { decJitCache_->Clear(); lastVType_ = -1; dec_ = nullptr; @@ -179,10 +180,11 @@ void DrawEngineCommon::Resized() { useHWTransform_ = g_Config.bHardwareTransform; useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation); + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize) { - const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); + const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode); VertexDecoder *dec = GetVertexDecoder(vertTypeID); if (vertexSize) *vertexSize = dec->VertexSize(); @@ -230,7 +232,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex } int bytesRead; - uint32_t vertTypeID = GetVertTypeID(vtype, 0); + uint32_t vertTypeID = GetVertTypeID(vtype, 0, decOptions_.applySkinInDecode); SubmitPrim(&temp[0], nullptr, prim, vertexCount, vertTypeID, cullMode, &bytesRead); DispatchFlush(); @@ -244,38 +246,52 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex // // It does the simplest and safest test possible: If all points of a bbox is outside a single of // our clipping planes, we reject the box. Tighter bounds would be desirable but would take more calculations. -bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCount, u32 vertType, int *bytesRead) { +bool DrawEngineCommon::TestBoundingBox(const void *control_points, const void *inds, int vertexCount, u32 vertType) { SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12); float *verts = (float *)(decoded + 65536 * 18); + // Although this may lead to drawing that shouldn't happen, the viewport is more complex on VR. + // Let's always say objects are within bounds. + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) + return true; + // Try to skip NormalizeVertices if it's pure positions. No need to bother with a vertex decoder // and a large vertex format. - if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT) { + if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT && !inds) { verts = (float *)control_points; - *bytesRead = 3 * sizeof(float) * vertexCount; - } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT) { + } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT && !inds) { const s8 *vtx = (const s8 *)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 128.0f); } - *bytesRead = 3 * sizeof(s8) * vertexCount; - } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT) { + } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT && !inds) { const s16 *vtx = (const s16*)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 32768.0f); } - *bytesRead = 3 * sizeof(s16) * vertexCount; } else { - // Simplify away bones and morph before proceeding + // Simplify away indices, bones, and morph before proceeding. u8 *temp_buffer = decoded + 65536 * 24; int vertexSize = 0; - NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)control_points, 0, vertexCount, vertType, &vertexSize); + + u16 indexLowerBound = 0; + u16 indexUpperBound = (u16)vertexCount - 1; + if (vertexCount > 0 && inds) { + GetIndexBounds(inds, vertexCount, vertType, &indexLowerBound, &indexUpperBound); + } + + // Force software skinning. + bool wasApplyingSkinInDecode = decOptions_.applySkinInDecode; + decOptions_.applySkinInDecode = true; + NormalizeVertices((u8 *)corners, temp_buffer, (const u8 *)control_points, indexLowerBound, indexUpperBound, vertType); + decOptions_.applySkinInDecode = wasApplyingSkinInDecode; + + IndexConverter conv(vertType, inds); for (int i = 0; i < vertexCount; i++) { - verts[i * 3] = corners[i].pos.x; - verts[i * 3 + 1] = corners[i].pos.y; - verts[i * 3 + 2] = corners[i].pos.z; + verts[i * 3] = corners[conv(i)].pos.x; + verts[i * 3 + 1] = corners[conv(i)].pos.y; + verts[i * 3 + 2] = corners[conv(i)].pos.z; } - *bytesRead = vertexSize * vertexCount; } Plane planes[6]; @@ -289,22 +305,63 @@ bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCou // TODO: Create a Matrix4x3ByMatrix4x3, and Matrix4x4ByMatrix4x3? Matrix4ByMatrix4(worldview, world, view); Matrix4ByMatrix4(worldviewproj, worldview, gstate.projMatrix); - PlanesFromMatrix(worldviewproj, planes); - for (int plane = 0; plane < 6; plane++) { + + // Next, we need to apply viewport, scissor, region, and even offset - but only for X/Y. + // Note that the PSP does not clip against the viewport. + const Vec2f baseOffset = Vec2f(gstate.getOffsetX(), gstate.getOffsetY()); + // Region1 (rate) is used as an X1/Y1 here, matching PSP behavior. + Vec2f minOffset = baseOffset + Vec2f(std::max(gstate.getRegionRateX() - 0x100, gstate.getScissorX1()), std::max(gstate.getRegionRateY() - 0x100, gstate.getScissorY1())) - Vec2f(1.0f, 1.0f); + Vec2f maxOffset = baseOffset + Vec2f(std::min(gstate.getRegionX2(), gstate.getScissorX2()), std::min(gstate.getRegionY2(), gstate.getScissorY2())) + Vec2f(1.0f, 1.0f); + + // Now let's apply the viewport to our scissor/region + offset range. + Vec2f inverseViewportScale = Vec2f(1.0f / gstate.getViewportXScale(), 1.0f / gstate.getViewportYScale()); + Vec2f minViewport = (minOffset - Vec2f(gstate.getViewportXCenter(), gstate.getViewportYCenter())) * inverseViewportScale; + Vec2f maxViewport = (maxOffset - Vec2f(gstate.getViewportXCenter(), gstate.getViewportYCenter())) * inverseViewportScale; + + Lin::Matrix4x4 applyViewport; + applyViewport.empty(); + // Scale to the viewport's size. + applyViewport.xx = 2.0f / (maxViewport.x - minViewport.x); + applyViewport.yy = 2.0f / (maxViewport.y - minViewport.y); + applyViewport.zz = 1.0f; + applyViewport.ww = 1.0f; + // And offset to the viewport's centers. + applyViewport.wx = -(maxViewport.x + minViewport.x) / (maxViewport.x - minViewport.x); + applyViewport.wy = -(maxViewport.y + minViewport.y) / (maxViewport.y - minViewport.y); + + float screenBounds[16]; + Matrix4ByMatrix4(screenBounds, worldviewproj, applyViewport.m); + + PlanesFromMatrix(screenBounds, planes); + // Note: near/far are not checked without clamp/clip enabled, so we skip those planes. + int totalPlanes = gstate.isDepthClampEnabled() ? 6 : 4; + for (int plane = 0; plane < totalPlanes; plane++) { int inside = 0; int out = 0; for (int i = 0; i < vertexCount; i++) { // Here we can test against the frustum planes! float value = planes[plane].Test(verts + i * 3); - if (value < 0) + if (value <= -FLT_EPSILON) out++; else inside++; } if (inside == 0) { - // All out - return false; + // All out - but check for X and Y if the offset was near the cullbox edge. + bool outsideEdge = false; + if (plane == 1) + outsideEdge = minOffset.x < 1.0f; + if (plane == 2) + outsideEdge = minOffset.y < 1.0f; + else if (plane == 0) + outsideEdge = maxOffset.x >= 4096.0f; + else if (plane == 3) + outsideEdge = maxOffset.y >= 4096.0f; + + // Only consider this outside if offset + scissor/region is fully inside the cullbox. + if (!outsideEdge) + return false; } // Any out. For testing that the planes are in the right locations. @@ -457,7 +514,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, }; // Let's have two separate loops, one for non skinning and one for skinning. - if (!g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { + if (!dec->skinInDecode && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { int numBoneWeights = vertTypeGetNumBoneWeights(vertType); for (int i = lowerBound; i <= upperBound; i++) { reader.Goto(i - lowerBound); @@ -467,7 +524,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } if (vertType & GE_VTYPE_COL_MASK) { - reader.ReadColor0_8888(sv.color); + sv.color_32 = reader.ReadColor0_8888(); } else { memcpy(sv.color, defaultColor, 4); } @@ -516,7 +573,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, sv.uv[1] = 0.0f; } if (vertType & GE_VTYPE_COL_MASK) { - reader.ReadColor0_8888(sv.color); + sv.color_32 = reader.ReadColor0_8888(); } else { memcpy(sv.color, defaultColor, 4); } @@ -537,7 +594,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } void DrawEngineCommon::ApplyFramebufferRead(FBOTexState *fboTexState) { - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) { *fboTexState = FBO_TEX_READ_FRAMEBUFFER; } else { gpuStats.numCopiesForShaderBlend++; @@ -779,7 +836,7 @@ void DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti numDrawCalls++; vertexCountInDrawCalls_ += vertexCount; - if (g_Config.bSoftwareSkinning && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) { DecodeVertsStep(decoded, decodeCounter_, decodedVerts_); decodeCounter_++; } diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 8fc0382a29..c5ac193c4c 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -52,10 +52,10 @@ enum FBOTexState { FBO_TEX_READ_FRAMEBUFFER, }; -inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { +inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode, bool skinInDecode) { // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it // into the top of the verttype where there are unused bits. - return (vertType & 0xFFFFFF) | (uvGenMode << 24); + return (vertType & 0xFFFFFF) | (uvGenMode << 24) | (skinInDecode << 26); } struct SimpleVertex; @@ -92,7 +92,7 @@ public: virtual void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation); - bool TestBoundingBox(const void* control_points, int vertexCount, u32 vertType, int *bytesRead); + bool TestBoundingBox(const void *control_points, const void *inds, int vertexCount, u32 vertType); void SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead); template @@ -105,7 +105,11 @@ public: std::vector DebugGetVertexLoaderIDs(); std::string DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType); - virtual void Resized(); + virtual void NotifyConfigChanged(); + + bool EverUsedExactEqualDepth() const { + return everUsedExactEqualDepth_; + } bool IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); @@ -145,11 +149,33 @@ protected: return 1; } + inline void UpdateEverUsedEqualDepth(GEComparison comp) { + switch (comp) { + case GE_COMP_EQUAL: + everUsedExactEqualDepth_ = true; + everUsedEqualDepth_ = true; + break; + + case GE_COMP_NOTEQUAL: + case GE_COMP_LEQUAL: + case GE_COMP_GEQUAL: + everUsedEqualDepth_ = true; + break; + + default: + break; + } + } + bool useHWTransform_ = false; bool useHWTessellation_ = false; // Used to prevent unnecessary flushing in softgpu. bool flushOnParams_ = true; + // Set once a equal depth test is encountered. + bool everUsedEqualDepth_ = false; + bool everUsedExactEqualDepth_ = false; + // Vertex collector buffers u8 *decoded = nullptr; u16 *decIndex = nullptr; diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index efd7c5a229..2d85308a92 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -31,21 +31,33 @@ #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderUniforms.h" #include "GPU/Common/FragmentShaderGenerator.h" +#include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #define WRITE(p, ...) p.F(__VA_ARGS__) +static const SamplerDef samplersMono[3] = { + { 0, "tex" }, + { 1, "fbotex", SamplerFlags::ARRAY_ON_VULKAN }, + { 2, "pal" }, +}; + +static const SamplerDef samplersStereo[3] = { + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, + { 1, "fbotex", SamplerFlags::ARRAY_ON_VULKAN }, + { 2, "pal" }, +}; + bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint64_t *uniformMask, FragmentShaderFlags *fragmentShaderFlags, std::string *errorString) { *uniformMask = 0; - if (fragmentShaderFlags) { - *fragmentShaderFlags = (FragmentShaderFlags)0; - } + *fragmentShaderFlags = (FragmentShaderFlags)0; errorString->clear(); + bool useStereo = id.Bit(FS_BIT_STEREO); bool highpFog = false; bool highpTexcoord = false; - bool enableFragmentTestCache = gstate_c.Supports(GPU_USE_FRAGMENT_TEST_CACHE); + bool enableFragmentTestCache = gstate_c.Use(GPU_USE_FRAGMENT_TEST_CACHE); if (compat.gles) { // PowerVR needs highp to do the fog in MHU correctly. @@ -55,26 +67,35 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } bool texture3D = id.Bit(FS_BIT_3D_TEXTURE); + bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE); ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); - std::vector gl_exts; + std::vector extensions; if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { - gl_exts.push_back("#extension GL_EXT_blend_func_extended : require"); + extensions.push_back("#extension GL_EXT_blend_func_extended : require"); } if (gl_extensions.EXT_gpu_shader4) { - gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); + extensions.push_back("#extension GL_EXT_gpu_shader4 : enable"); } if (compat.framebufferFetchExtension) { - gl_exts.push_back(compat.framebufferFetchExtension); + extensions.push_back(compat.framebufferFetchExtension); } if (gl_extensions.OES_texture_3D && texture3D) { - gl_exts.push_back("#extension GL_OES_texture_3D: enable"); + extensions.push_back("#extension GL_OES_texture_3D: enable"); } + } + + ShaderWriterFlags flags = ShaderWriterFlags::NONE; + if (useStereo) { + flags |= ShaderWriterFlags::FS_AUTO_STEREO; } - ShaderWriter p(buffer, compat, ShaderStage::Fragment, gl_exts.data(), gl_exts.size()); + ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions, flags); + p.F("// %s\n", FragmentShaderDesc(id).c_str()); + + p.ApplySamplerMetadata(arrayTexture ? samplersStereo : samplersMono); bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); @@ -89,6 +110,15 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ); bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA); + if (texture3D && arrayTexture) { + *errorString = "Invalid combination of 3D texture and array texture, shouldn't happen"; + return false; + } + if (compat.shaderLanguage != ShaderLanguage::GLSL_VULKAN && arrayTexture) { + *errorString = "We only do array textures for framebuffers in Vulkan."; + return false; + } + bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled; bool doFlatShading = id.Bit(FS_BIT_FLATSHADE) && !flatBug; @@ -137,38 +167,45 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool needFramebufferRead = replaceBlend == REPLACE_BLEND_READ_FRAMEBUFFER || colorWriteMask || replaceLogicOp; - bool fetchFramebuffer = needFramebufferRead && gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); - bool readFramebufferTex = needFramebufferRead && !gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH); + bool fetchFramebuffer = needFramebufferRead && id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); + bool readFramebufferTex = needFramebufferRead && !id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH); - bool needFragCoord = readFramebufferTex || gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); - bool writeDepth = gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + if (fetchFramebuffer && compat.shaderLanguage != GLSL_VULKAN && (compat.shaderLanguage != GLSL_3xx || !compat.lastFragData)) { + *errorString = "framebuffer fetch requires GLSL: vulkan or 3xx"; + return false; + } + + bool needFragCoord = readFramebufferTex || gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); if (shaderDepalMode != ShaderDepalMode::OFF && !doTexture) { *errorString = "depal requires a texture"; return false; } + // Currently only used by Vulkan. + std::vector samplers; + if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN) { - if (useDiscardStencilBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { + if (useDiscardStencilBugWorkaround && !gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform baseUBO {\n%s};\n", DRAW_BINDING_DYNUBO_BASE, ub_baseStr); if (doTexture) { - WRITE(p, "layout (binding = 0) uniform %s tex;\n", texture3D ? "sampler3D" : "sampler2D"); + WRITE(p, "layout (set = 1, binding = %d) uniform %s%s tex;\n", DRAW_BINDING_TEXTURE, texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); } if (readFramebufferTex) { - WRITE(p, "layout (binding = 1) uniform sampler2D fbotex;\n"); + // The framebuffer texture is always bound as an array. + p.F("layout (set = 1, binding = %d) uniform sampler2DArray fbotex;\n", DRAW_BINDING_2ND_TEXTURE); } else if (fetchFramebuffer) { - WRITE(p, "layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n"); - if (fragmentShaderFlags) { - *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; - } + p.F("layout (input_attachment_index = 0, set = 1, binding = %d) uniform subpassInput inputColor;\n", DRAW_BINDING_INPUT_ATTACHMENT); + *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; } if (shaderDepalMode != ShaderDepalMode::OFF) { - WRITE(p, "layout (binding = 2) uniform sampler2D pal;\n"); + WRITE(p, "layout (set = 1, binding = %d) uniform sampler2D pal;\n", DRAW_BINDING_DEPAL_TEXTURE); } // Note: the precision qualifiers must match the vertex shader! @@ -514,6 +551,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " vec4 destColor = fbotex.Load(int3((int)gl_FragCoord.x, (int)gl_FragCoord.y, 0));\n"); } else if (compat.shaderLanguage == HLSL_D3D9) { WRITE(p, " vec4 destColor = tex2D(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); + } else if (compat.shaderLanguage == GLSL_VULKAN) { + WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec3(gl_FragCoord.x, gl_FragCoord.y, %s), 0);\n", compat.texelFetch, useStereo ? "float(gl_ViewIndex)" : "0"); } else if (!compat.texelFetch) { WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); } else { @@ -525,7 +564,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (compat.shaderLanguage == GLSL_3xx) { WRITE(p, " lowp vec4 destColor = %s;\n", compat.lastFragData); } else if (compat.shaderLanguage == GLSL_VULKAN) { - WRITE(p, " lowp vec4 destColor = subpassLoad(inputColor);\n", compat.lastFragData); + WRITE(p, " lowp vec4 destColor = subpassLoad(inputColor);\n"); } else { _assert_msg_(false, "Need fetch destColor, but not a compatible language"); } @@ -628,6 +667,18 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } else { WRITE(p, " vec4 t = %s(tex, vec3(%s.xy, u_mipBias));\n", compat.texture3D, texcoord); } + } else if (arrayTexture) { + _dbg_assert_(compat.shaderLanguage == GLSL_VULKAN); + // Used for stereo rendering. + const char *arrayIndex = useStereo ? "float(gl_ViewIndex)" : "0.0"; + if (doTextureProjection) { + // There's no textureProj for array textures, so we need to emulate it. + // Should be fine on any Vulkan-compatible hardware. + WRITE(p, " vec2 uv_proj = (%s.xy) / (%s.z);\n", texcoord, texcoord); + WRITE(p, " vec4 t = %s(tex, vec3(uv_proj, %s));\n", compat.texture, texcoord, arrayIndex); + } else { + WRITE(p, " vec4 t = %s(tex, vec3(%s.xy, %s));\n", compat.texture, texcoord, arrayIndex); + } } else { if (doTextureProjection) { WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord); @@ -867,6 +918,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu const char *discardStatement = testForceToZero ? "v.a = 0.0;" : "DISCARD;"; if (enableAlphaTest) { + *fragmentShaderFlags |= FragmentShaderFlags::USES_DISCARD; + if (alphaTestAgainstZero) { // When testing against 0 (extremely common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. @@ -904,6 +957,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } if (enableColorTest) { + *fragmentShaderFlags |= FragmentShaderFlags::USES_DISCARD; + if (colorTestAgainstZero) { // When testing against 0 (common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. @@ -1173,11 +1228,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " %s = vec4(0.0, 0.0, 0.0, %s.z); // blue to alpha\n", compat.fragColor0, compat.fragColor0); } - if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { + if (gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { const double scale = DepthSliceFactor() * 65535.0; WRITE(p, " highp float z = gl_FragCoord.z;\n"); - if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { // We center the depth with an offset, but only its fraction matters. // When (DepthSliceFactor() - 1) is odd, it will be 0.5, otherwise 0. if (((int)(DepthSliceFactor() - 1.0f) & 1) == 1) { diff --git a/GPU/Common/FragmentShaderGenerator.h b/GPU/Common/FragmentShaderGenerator.h index 8f358fa7ff..88c2c3f9d6 100644 --- a/GPU/Common/FragmentShaderGenerator.h +++ b/GPU/Common/FragmentShaderGenerator.h @@ -43,6 +43,7 @@ struct FShaderID; // Can technically be deduced from the fragment shader ID, but this is safer. enum class FragmentShaderFlags : u32 { INPUT_ATTACHMENT = 1, + USES_DISCARD = 2, }; ENUM_CLASS_BITOPS(FragmentShaderFlags); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 7195c9fc6e..9a372da426 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -27,6 +27,7 @@ #include "Common/Math/lin/matrix4x4.h" #include "Common/Math/math_util.h" #include "Common/System/Display.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/CommonTypes.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -49,7 +50,7 @@ #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" -static size_t FormatFramebufferName(VirtualFramebuffer *vfb, char *tag, size_t len) { +static size_t FormatFramebufferName(const VirtualFramebuffer *vfb, char *tag, size_t len) { return snprintf(tag, len, "FB_%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, vfb->bufferWidth, vfb->bufferHeight, GeBufferFormatToString(vfb->fb_format)); } @@ -81,33 +82,47 @@ FramebufferManagerCommon::~FramebufferManagerCommon() { delete presentation_; } -void FramebufferManagerCommon::Init() { +void FramebufferManagerCommon::Init(int msaaLevel) { // We may need to override the render size if the shader is upscaling or SSAA. - Resized(); + NotifyDisplayResized(); + NotifyRenderResized(msaaLevel); } -bool FramebufferManagerCommon::UpdateSize() { - const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight; +bool FramebufferManagerCommon::UpdateRenderSize(int msaaLevel) { + const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight || msaaLevel_ != msaaLevel; - const int effectiveBloomHack = PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn ? 3 : g_Config.iBloomHack; + int effectiveBloomHack = g_Config.iBloomHack; + if (PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOn) { + effectiveBloomHack = 3; + } else if (PSP_CoreParameter().compat.flags().ForceLowerResolutionForEffectsOff) { + effectiveBloomHack = 0; + } - const bool newSettings = bloomHack_ != effectiveBloomHack || useBufferedRendering_ != (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE); + bool newBuffered = !g_Config.bSkipBufferEffects; + const bool newSettings = bloomHack_ != effectiveBloomHack || useBufferedRendering_ != newBuffered; renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; renderScaleFactor_ = (float)PSP_CoreParameter().renderScaleFactor; - pixelWidth_ = PSP_CoreParameter().pixelWidth; - pixelHeight_ = PSP_CoreParameter().pixelHeight; + msaaLevel_ = msaaLevel; + bloomHack_ = effectiveBloomHack; - useBufferedRendering_ = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - - presentation_->UpdateSize(pixelWidth_, pixelHeight_, renderWidth_, renderHeight_); + useBufferedRendering_ = newBuffered; + presentation_->UpdateRenderSize(renderWidth_, renderHeight_); return newRender || newSettings; } +void FramebufferManagerCommon::CheckPostShaders() { + if (updatePostShaders_) { + presentation_->UpdatePostShader(); + updatePostShaders_ = false; + } +} + void FramebufferManagerCommon::BeginFrame() { DecimateFBOs(); + currentRenderVfb_ = nullptr; } @@ -414,7 +429,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer vfb->height = drawing_height; } break; - } else if (v->fb_stride == params.fb_stride && v->fb_format == params.fb_format && !PSP_CoreParameter().compat.flags().SplitFramebufferMargin) { + } else if (!PSP_CoreParameter().compat.flags().DisallowFramebufferAtOffset && v->fb_stride == params.fb_stride && v->fb_format == params.fb_format && !PSP_CoreParameter().compat.flags().SplitFramebufferMargin) { u32 v_fb_first_line_end_ptr = v->fb_address + v->fb_stride * bpp; u32 v_fb_end_ptr = v->fb_address + v->fb_stride * v->height * bpp; @@ -655,7 +670,7 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra // for (auto &source : sources) { if (!sources.empty()) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); auto &source = sources.back(); if (source.channel == RASTER_DEPTH) { @@ -795,7 +810,7 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra std::sort(sources.begin(), sources.end()); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); bool tookActions = false; @@ -935,36 +950,32 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir bool useCopy = draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported); bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; - bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported; + bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported && draw_->GetDeviceCaps().textureDepthSupported; - // Could do an attempt at optimization - if destination already bound, draw depth using raster. - // Let's experiment later, commented out for now. Currently we fall back to raster as a last resort here. - - /* - if (currentRenderVfb_ == dst) { - useCopy = false; - useBlit = false; + if (src->fbo->MultiSampleLevel() > 0 && dst->fbo->MultiSampleLevel() > 0) { + // If multisampling, we want to copy depth properly so we get all the samples, to avoid aliased edges. + // Can be seen in the fire in Jeanne D'arc, for example. + if (useRaster && useCopy) { + useRaster = false; + } } - */ int w = std::min(src->renderWidth, dst->renderWidth); int h = std::min(src->renderHeight, dst->renderHeight); - // TODO: It might even be advantageous on some GPUs to do this copy using a fragment shader that writes to Z, that way upcoming commands can just continue that render pass. - // Some GPUs can copy depth but only if stencil gets to come along for the ride. We only want to use this if there is no blit functionality. - if (useCopy) { + if (useRaster) { + BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, dst->renderScaleFactor, Get2DPipeline(Draw2DShader::DRAW2D_COPY_DEPTH), "BlitDepthRaster"); + } else if (useCopy) { draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "CopyFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); } else if (useBlit) { // We'll accept whether we get a separate depth blit or not... draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); - } else if (useRaster) { - BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, dst->renderScaleFactor, Get2DPipeline(Draw2DShader::DRAW2D_COPY_DEPTH), "BlitDepthRaster"); } - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); } void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) { @@ -1004,7 +1015,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe if (useBufferedRendering_) { if (vfb->fbo) { shaderManager_->DirtyLastShader(); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "FBSwitch"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch"); } else { // This should only happen very briefly when toggling useBufferedRendering_. ResizeFramebufFBO(vfb, vfb->width, vfb->height, true); @@ -1133,20 +1144,23 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height); if (pixelsTex) { - draw_->BindTextures(0, 1, &pixelsTex); + draw_->BindTextures(0, 1, &pixelsTex, Draw::TextureBindFlags::VULKAN_BIND_ARRAY); // TODO: Replace with draw2D_.Blit() directly. - DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); + DrawActiveTexture(dstX, dstY, width, height, + vfb ? vfb->bufferWidth : pixel_xres, + vfb ? vfb->bufferHeight : pixel_yres, + u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); gpuStats.numUploads++; pixelsTex->Release(); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } } -bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { +bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer) { if (!framebuffer->fbo || !useBufferedRendering_) { draw_->BindTexture(stage, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; @@ -1166,17 +1180,17 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF if (renderCopy) { VirtualFramebuffer copyInfo = *framebuffer; copyInfo.fbo = renderCopy; - CopyFramebufferForColorTexture(©Info, framebuffer, flags); + CopyFramebufferForColorTexture(©Info, framebuffer, flags, layer); RebindFramebuffer("After BindFramebufferAsColorTexture"); - draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, layer); gpuStats.numCopiesForSelfTex++; } else { // Failed to get temp FBO? Weird. - draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, layer); } return true; } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { - draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, layer); return true; } else { ERROR_LOG_REPORT_ONCE(selfTextureFail, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); @@ -1190,7 +1204,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF } } -void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags) { +void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer) { int x = 0; int y = 0; int w = src->drawnWidth; @@ -1220,6 +1234,20 @@ void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer } Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) { + Draw::DataFormat depthFormat = Draw::DataFormat::UNDEFINED; + if (srcPixelFormat == GE_FORMAT_DEPTH16) { + if ((draw_->GetDataFormatSupport(Draw::DataFormat::R16_UNORM) & Draw::FMT_TEXTURE) != 0) { + depthFormat = Draw::DataFormat::R16_UNORM; + } else if ((draw_->GetDataFormatSupport(Draw::DataFormat::R8_UNORM) & Draw::FMT_TEXTURE) != 0) { + // This could be improved by using specific draw shaders to pack full precision in two channels. + // However, not really worth the trouble until we find a game that requires it. + depthFormat = Draw::DataFormat::R8_UNORM; + } else { + // No usable single channel format. Can't be bothered. + return nullptr; + } + } + // TODO: We can just change the texture format and flip some bits around instead of this. // Could share code with the texture cache perhaps. auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) { @@ -1228,6 +1256,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y; u32 *dst = (u32 *)(data + byteStride * y); u16 *dst16 = (u16 *)(data + byteStride * y); + u8 *dst8 = (u8 *)(data + byteStride * y); switch (srcPixelFormat) { case GE_FORMAT_565: if (preferredPixelsFormat_ == Draw::DataFormat::B8G8R8A8_UNORM) @@ -1266,7 +1295,16 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G // to do one of two different swizzle operations. However, for the only use of this so far, // the Burnout lens flare trickery, swizzle doesn't matter since it's just a 0, 7fff, 0, 7fff pattern // which comes out the same. - memcpy(dst16, src16, w * 2); + if (depthFormat == Draw::DataFormat::R16_UNORM) { + // We just use this format straight. + memcpy(dst16, src16, w * 2); + } else if (depthFormat == Draw::DataFormat::R8_UNORM) { + // We fall back to R8_UNORM. Precision is enough for most cases of depth clearing and initialization we've seen, + // but hardly ideal. + for (int i = 0; i < width; i++) { + dst8[i] = src16[i] >> 8; + } + } break; case GE_FORMAT_INVALID: @@ -1282,7 +1320,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G // and likely more efficient. Draw::TextureDesc desc{ Draw::TextureType::LINEAR2D, - srcPixelFormat == GE_FORMAT_DEPTH16 ? Draw::DataFormat::R16_UNORM : preferredPixelsFormat_, + srcPixelFormat == GE_FORMAT_DEPTH16 ? depthFormat : preferredPixelsFormat_, width, height, 1, @@ -1337,7 +1375,7 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v // Some games will draw to some memory once, and use it as a render-to-texture later. // To support this, we save the first frame to memory when we have a safe w/h. // Saving each frame would be slow. - if (g_Config.bBlockTransferGPU && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { + if (!g_Config.bSkipGPUReadbacks && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight, RASTER_COLOR); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->safeWidth = 0; @@ -1356,10 +1394,12 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { shaderManager_->DirtyLastShader(); if (displayFramebufPtr_ == 0) { - if (Core_IsStepping()) - VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); - else - DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); + if (GetUIState() != UISTATE_PAUSEMENU) { + if (Core_IsStepping()) + VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); + else + DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); + } // No framebuffer to display! Clear to black. if (useBufferedRendering_) { draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput"); @@ -1447,16 +1487,33 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { displayFramebuf_ = vfb; if (vfb->fbo) { - if (Core_IsStepping()) - VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); - else - DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + if (GetUIState() != UISTATE_PAUSEMENU) { + if (Core_IsStepping()) + VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + else + DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + } float u0 = offsetX / (float)vfb->bufferWidth; float v0 = offsetY / (float)vfb->bufferHeight; float u1 = (480.0f + offsetX) / (float)vfb->bufferWidth; float v1 = (272.0f + offsetY) / (float)vfb->bufferHeight; + //clip the VR framebuffer to keep the aspect ratio + if (IsVREnabled() && !IsFlatVRGame() && !IsGameVRScene()) { + float aspect = 272.0f / 480.0f; + float clipY = 272.0f * (1.0f - aspect) / 2.0f; + v0 = (clipY + offsetY) / (float)vfb->bufferHeight; + v1 = (272.0f - clipY + offsetY) / (float)vfb->bufferHeight; + + //zoom inside + float zoom = 0.1f; + u0 += zoom / aspect; + u1 -= zoom / aspect; + v0 += zoom; + v1 -= zoom; + } + textureCache_->ForgetLastTexture(); int uvRotation = useBufferedRendering_ ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL; @@ -1612,7 +1669,8 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, shaderManager_->DirtyLastShader(); char tag[128]; size_t len = FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, tag }); + + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), msaaLevel_, true, tag }); if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) { NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len); } @@ -1797,7 +1855,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, FlushBeforeCopy(); if (srcH == 0 || srcY + srcH > srcBuffer->bufferHeight) { WARN_LOG_ONCE(btdcpyheight, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); - } else if (g_Config.bBlockTransferGPU && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { + } else if (!g_Config.bSkipGPUReadbacks && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH, channel); srcBuffer->usageFlags = (srcBuffer->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; } @@ -1939,7 +1997,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p } } - if (!candidates.empty()) { + if (best) { *rect = *best; return true; } else { @@ -1979,7 +2037,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd char name[64]; snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address); textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, name }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, name }); vfbs_.push_back(vfb); u32 byteSize = ColorBufferByteSize(vfb); @@ -2032,7 +2090,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram snprintf(name, sizeof(name), "download_temp"); // TODO: We don't have a way to create a depth-only framebuffer yet. // Also, at least on Vulkan we always create both depth and color, need to rework how we handle renderpasses. - nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, channel == RASTER_DEPTH ? true : false, name }); + nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 0, channel == RASTER_DEPTH ? true : false, name }); if (!nvfb->fbo) { ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight); delete nvfb; @@ -2253,7 +2311,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride); FlushBeforeCopy(); - if (g_Config.bBlockTransferGPU && !srcRect.vfb->memoryUpdated) { + if (!g_Config.bSkipGPUReadbacks && !srcRect.vfb->memoryUpdated) { const int srcBpp = BufferFormatBytesPerPixel(srcRect.vfb->fb_format); const float srcXFactor = (float)bpp / srcBpp; const bool tooTall = srcY + srcRect.h > srcRect.vfb->bufferHeight; @@ -2336,7 +2394,17 @@ void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) { } } -void FramebufferManagerCommon::Resized() { +void FramebufferManagerCommon::NotifyDisplayResized() { + pixelWidth_ = PSP_CoreParameter().pixelWidth; + pixelHeight_ = PSP_CoreParameter().pixelHeight; + presentation_->UpdateDisplaySize(pixelWidth_, pixelHeight_); + + // No drawing is allowed here. This includes anything that might potentially touch a command buffer, like creating images! + // So we need to defer the post processing initialization. + updatePostShaders_ = true; +} + +void FramebufferManagerCommon::NotifyRenderResized(int msaaLevel) { gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; int w, h, scaleFactor; @@ -2345,12 +2413,13 @@ void FramebufferManagerCommon::Resized() { PSP_CoreParameter().renderHeight = h; PSP_CoreParameter().renderScaleFactor = scaleFactor; - if (UpdateSize()) { + if (UpdateRenderSize(msaaLevel)) { DestroyAllFBOs(); } - // Might have a new post shader - let's compile it. - presentation_->UpdatePostShader(); + // No drawing is allowed here. This includes anything that might potentially touch a command buffer, like creating images! + // So we need to defer the post processing initialization. + updatePostShaders_ = true; #ifdef _WIN32 // Seems related - if you're ok with numbers all the time, show some more :) @@ -2360,6 +2429,10 @@ void FramebufferManagerCommon::Resized() { #endif } +void FramebufferManagerCommon::NotifyConfigChanged() { + updatePostShaders_ = true; +} + void FramebufferManagerCommon::DestroyAllFBOs() { currentRenderVfb_ = nullptr; displayFramebuf_ = nullptr; @@ -2388,6 +2461,17 @@ void FramebufferManagerCommon::DestroyAllFBOs() { fbosToDelete_.clear(); } +static const char *TempFBOReasonToString(TempFBO reason) { + switch (reason) { + case TempFBO::DEPAL: return "depal"; + case TempFBO::BLIT: return "blit"; + case TempFBO::COPY: return "copy"; + case TempFBO::STENCIL: return "stencil"; + default: break; + } + return ""; +} + Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h) { u64 key = ((u64)reason << 48) | ((u32)w << 16) | h; auto it = tempFBOs_.find(key); @@ -2398,8 +2482,9 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u bool z_stencil = reason == TempFBO::STENCIL; char name[128]; - snprintf(name, sizeof(name), "temp_fbo_%dx%d%s", w / renderScaleFactor_, h / renderScaleFactor_, z_stencil ? "_depth" : ""); - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, name }); + snprintf(name, sizeof(name), "tempfbo_%s_%dx%d", TempFBOReasonToString(reason), w / renderScaleFactor_, h / renderScaleFactor_); + + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), 0, z_stencil, name }); if (!fbo) { return nullptr; } @@ -2532,7 +2617,7 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 } bool flipY = (GetGPUBackend() == GPUBackend::OPENGL && !useBufferedRendering_) ? true : false; - if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT_DIV_256, flipY); } else { buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY); @@ -2710,7 +2795,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, } } - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); textureCache_->ForgetLastTexture(); RebindFramebuffer("RebindFramebuffer - ReadFramebufferToMemory"); } @@ -2773,8 +2858,10 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo } void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); + // Needed for D3D11 to run validation clean. I don't think it's actually an issue. + // textureCache_->ForgetLastTexture(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); } else { @@ -2807,11 +2894,7 @@ static void DoRelease(T *&obj) { obj = nullptr; } -void FramebufferManagerCommon::DeviceLost() { - DestroyAllFBOs(); - - presentation_->DeviceLost(); - +void FramebufferManagerCommon::ReleasePipelines() { for (int i = 0; i < ARRAY_SIZE(reinterpretFromTo_); i++) { for (int j = 0; j < ARRAY_SIZE(reinterpretFromTo_); j++) { DoRelease(reinterpretFromTo_[i][j]); @@ -2828,9 +2911,16 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(draw2DPipelineDepth_); DoRelease(draw2DPipeline565ToDepth_); DoRelease(draw2DPipeline565ToDepthDeswizzle_); +} +void FramebufferManagerCommon::DeviceLost() { + DestroyAllFBOs(); + + presentation_->DeviceLost(); draw2D_.DeviceLost(); + ReleasePipelines(); + draw_ = nullptr; } @@ -2931,9 +3021,9 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX bool useBlit = channel == RASTER_COLOR ? draw_->GetDeviceCaps().framebufferBlitSupported : false; bool useCopy = channel == RASTER_COLOR ? draw_->GetDeviceCaps().framebufferCopySupported : false; - if (dst == currentRenderVfb_) { + if (dst == currentRenderVfb_ || dst->fbo->MultiSampleLevel() != 0 || src->fbo->MultiSampleLevel() != 0) { // If already bound, using either a blit or a copy is unlikely to be an optimization. - // So we're gonna use a raster draw instead. + // So we're gonna use a raster draw instead. Also multisampling has problems with copies currently. useBlit = false; useCopy = false; } @@ -2997,7 +3087,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false, dst->renderScaleFactor, pipeline, tag); } - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } @@ -3022,7 +3112,7 @@ void FramebufferManagerCommon::BlitUsingRaster( draw_->BindTexture(0, nullptr); // This will get optimized away in case it's already bound (in VK and GL at least..) draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster"); - draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); + draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, Draw::ALL_LAYERS); if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) { // We overwrite the whole channel of the framebuffer, so we can invalidate the current contents. @@ -3038,6 +3128,14 @@ void FramebufferManagerCommon::BlitUsingRaster( gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } +int FramebufferManagerCommon::GetFramebufferLayers() const { + int layers = 1; + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + layers = 2; + } + return layers; +} + VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(VirtualFramebuffer *src, GEBufferFormat newFormat) { // Look for an identical framebuffer with the new format _dbg_assert_(src->fb_format != newFormat); @@ -3081,7 +3179,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi char tag[128]; FormatFramebufferName(vfb, tag, sizeof(tag)); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, tag }); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, true, tag }); vfbs_.push_back(vfb); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index ffcab7a1ec..b900104b7e 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -204,8 +204,6 @@ enum class TempFBO { BLIT, // For copies of framebuffers (e.g. shader blending.) COPY, - // For another type of framebuffers that can happen together with COPY (see Outrun) - REINTERPRET, // Used to copy stencil data, means we need a stencil backing. STENCIL, }; @@ -274,7 +272,7 @@ public: drawEngine_ = td; } - virtual void Init(); + void Init(int msaaLevel); virtual void BeginFrame(); void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); void DestroyFramebuf(VirtualFramebuffer *v); @@ -322,7 +320,7 @@ public: // Otherwise it doesn't get called. void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason); - bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); + bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer); void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes); @@ -400,7 +398,12 @@ public: } void SetSafeSize(u16 w, u16 h); - virtual void Resized(); + void NotifyRenderResized(int msaaLevel); + virtual void NotifyDisplayResized(); + void NotifyConfigChanged(); + + void CheckPostShaders(); + virtual void DestroyAllFBOs(); virtual void DeviceLost(); @@ -440,6 +443,12 @@ public: int scaleFactor, // usually unused, except for swizzle... Draw2DPipeline *pipeline, const char *tag); + void ReleasePipelines(); + + int GetMSAALevel() const { + return msaaLevel_; + } + protected: virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); // Used for when a shader is required, such as GLES. @@ -452,7 +461,7 @@ protected: void CopyToColorFromOverlappingFramebuffers(VirtualFramebuffer *dest); void CopyToDepthFromOverlappingFramebuffers(VirtualFramebuffer *dest); - bool UpdateSize(); + bool UpdateRenderSize(int msaaLevel); void FlushBeforeCopy(); virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra @@ -460,7 +469,7 @@ protected: // Used by ReadFramebufferToMemory and later framebuffer block copies void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, RasterChannel channel, const char *tag); - void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags); + void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer); void EstimateDrawingSize(u32 fb_address, int fb_stride, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int &drawing_width, int &drawing_height); u32 ColorBufferByteSize(const VirtualFramebuffer *vfb) const; @@ -486,6 +495,8 @@ protected: void UpdateFramebufUsage(VirtualFramebuffer *vfb); + int GetFramebufferLayers() const; + static void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) { dstBuffer->memoryUpdated = false; dstBuffer->clutUpdatedBytes = 0; @@ -540,10 +551,12 @@ protected: float renderWidth_ = 0.0f; float renderHeight_ = 0.0f; + int msaaLevel_ = 0; int renderScaleFactor_ = 1; int pixelWidth_ = 0; int pixelHeight_ = 0; int bloomHack_ = 0; + bool updatePostShaders_ = false; Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM; diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index a94a3b46a1..618c958a1f 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -19,6 +19,7 @@ #include "Common/Math/expression_parser.h" #include "Core/Debugger/SymbolMap.h" #include "GPU/Common/GPUDebugInterface.h" +#include "GPU/Debugger/Debugger.h" #include "GPU/Debugger/GECommandTable.h" #include "GPU/GPUState.h" @@ -34,6 +35,8 @@ enum class GEReferenceIndex : uint32_t { CLUTADDR, TRANSFERSRC, TRANSFERDST, + PRIMCOUNT, + LASTPRIMCOUNT, TEXADDR0, TEXADDR1, @@ -74,6 +77,8 @@ static constexpr ReferenceName referenceNames[] = { { GEReferenceIndex::CLUTADDR, "clutaddr" }, { GEReferenceIndex::TRANSFERSRC, "transfersrc" }, { GEReferenceIndex::TRANSFERDST, "transferdst" }, + { GEReferenceIndex::PRIMCOUNT, "primcount" }, + { GEReferenceIndex::LASTPRIMCOUNT, "lastprimcount" }, { GEReferenceIndex::TEXADDR0, "texaddr0" }, { GEReferenceIndex::TEXADDR1, "texaddr1" }, { GEReferenceIndex::TEXADDR2, "texaddr2" }, @@ -695,6 +700,12 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { case GEReferenceIndex::TRANSFERDST: return state.getTransferDstAddress(); + case GEReferenceIndex::PRIMCOUNT: + return GPUDebug::PrimsThisFrame(); + + case GEReferenceIndex::LASTPRIMCOUNT: + return GPUDebug::PrimsLastFrame(); + case GEReferenceIndex::TEXADDR0: case GEReferenceIndex::TEXADDR1: case GEReferenceIndex::TEXADDR2: @@ -916,20 +927,19 @@ ExpressionType GEExpressionFunctions::getFieldType(GECmdFormat fmt, GECmdField f } bool GEExpressionFunctions::getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) { - if (!Memory::IsValidRange(address, size)) { - sprintf(error, "Invalid address or size %08x + %d", address, size); - return false; - } + // We allow, but ignore, bad access. + // If we didn't, log/condition statements that reference registers couldn't be configured. + bool valid = Memory::IsValidRange(address, size); switch (size) { case 1: - dest = Memory::Read_U8(address); + dest = valid ? Memory::Read_U8(address) : 0; return true; case 2: - dest = Memory::Read_U16(address); + dest = valid ? Memory::Read_U16(address) : 0; return true; case 4: - dest = Memory::Read_U32(address); + dest = valid ? Memory::Read_U32(address) : 0; return true; } diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index 7bc5e43baa..b67fca66f3 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -190,6 +190,7 @@ struct GPUDebugVertex { class GPUDebugInterface { public: + virtual ~GPUDebugInterface() {} virtual bool GetCurrentDisplayList(DisplayList &list) = 0; virtual std::vector ActiveDisplayLists() = 0; virtual void ResetListPC(int listID, u32 pc) = 0; diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2b8bb84dc1..f902330528 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -136,6 +136,15 @@ bool IsColorTestTriviallyTrue() { } } +bool IsDepthTestEffectivelyDisabled() { + if (!gstate.isDepthTestEnabled()) + return true; + // We can ignore stencil, because ALWAYS and disabled choose the same stencil path. + if (gstate.getDepthTestFunction() != GE_COMP_ALWAYS) + return false; + return !gstate.isDepthWriteEnabled(); +} + const bool nonAlphaSrcFactors[16] = { true, // GE_SRCBLEND_DSTCOLOR, true, // GE_SRCBLEND_INVDSTCOLOR, @@ -183,7 +192,7 @@ ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) { if (nonAlphaSrcFactors[gstate.getBlendFuncA()] && nonAlphaDestFactors[gstate.getBlendFuncB()]) { return REPLACE_ALPHA_YES; } else { - if (gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) { + if (gstate_c.Use(GPU_USE_DUALSOURCE_BLEND)) { return REPLACE_ALPHA_DUALSOURCE; } else { return REPLACE_ALPHA_NO; @@ -275,7 +284,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_BLENDMODE_MIN: case GE_BLENDMODE_MAX: - if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) { + if (gstate_c.Use(GPU_USE_BLEND_MINMAX)) { return REPLACE_BLEND_STANDARD; } else { return REPLACE_BLEND_READ_FRAMEBUFFER; @@ -312,7 +321,7 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: // We can't technically do this correctly (due to clamping) without reading the dst color. // Using a copy isn't accurate either, though, when there's overlap. - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; @@ -454,14 +463,14 @@ ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat) { case GE_DSTBLEND_DOUBLESRCALPHA: if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; } else { // This means dst alpha/color is used in the src factor. // Unfortunately, copying here causes overlap problems in Silent Hill games (it seems?) // We will just hope that doubling alpha for the dst factor will not clamp too badly. - if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) return REPLACE_BLEND_READ_FRAMEBUFFER; return REPLACE_BLEND_2X_ALPHA; } @@ -494,10 +503,10 @@ static const float DEPTH_SLICE_FACTOR_HIGH = 4.0f; static const float DEPTH_SLICE_FACTOR_16BIT = 256.0f; float DepthSliceFactor() { - if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { return DEPTH_SLICE_FACTOR_16BIT; } - if (gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP)) { + if (gstate_c.Use(GPU_USE_DEPTH_CLAMP)) { return 1.0f; } return DEPTH_SLICE_FACTOR_HIGH; @@ -505,12 +514,12 @@ float DepthSliceFactor() { // This is used for float values which might not be integers, but are in the integer scale of 65535. float ToScaledDepthFromIntegerScale(float z) { - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { return z * (1.0f / 65535.0f); } const float depthSliceFactor = DepthSliceFactor(); - if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { const double doffset = 0.5 * (depthSliceFactor - 1.0) * (1.0 / depthSliceFactor); // Use one bit for each value, rather than 1.0 / (25535.0 * 256.0). return (float)((double)z * (1.0 / 16777215.0) + doffset); @@ -523,7 +532,7 @@ float ToScaledDepthFromIntegerScale(float z) { // See struct DepthScaleFactors for how to apply. DepthScaleFactors GetDepthScaleFactors() { DepthScaleFactors factors; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { factors.offset = 0; factors.scale = 65535.0f; return factors; @@ -728,7 +737,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // This adjusts the center from halfActualZRange to vpZCenter. out.zOffset = halfActualZRange < std::numeric_limits::epsilon() ? 0.0f : (vpZCenter - (minz + halfActualZRange)) / halfActualZRange; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { out.depthScale = 1.0f; out.zOffset = 0.0f; out.depthRangeMin = ToScaledDepthFromIntegerScale(vpZCenter - vpZScale); @@ -858,9 +867,12 @@ static inline bool blendColorSimilar(uint32_t a, uint32_t b, int margin = 25) { // The shader might also need modification, the below function SimulateLogicOpShaderTypeIfNeeded // takes care of that. static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) { + if (!gstate.isLogicOpEnabled()) + return false; + // Note: our shader solution applies logic ops BEFORE blending, not correctly after. // This is however fine for the most common ones, like CLEAR/NOOP/SET, etc. - if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP) && gstate.isLogicOpEnabled()) { + if (!gstate_c.Use(GPU_USE_LOGIC_OP)) { switch (gstate.getLogicOp()) { case GE_LOGIC_CLEAR: srcBlend = BlendFactor::ZERO; @@ -916,13 +928,32 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp()); return true; } + } else { + // Even if we support hardware logic ops, alpha is handled wrong. + // It's better to override blending for the simple cases. + switch (gstate.getLogicOp()) { + case GE_LOGIC_CLEAR: + srcBlend = BlendFactor::ZERO; + dstBlend = BlendFactor::ZERO; + blendEq = BlendEq::ADD; + return true; + case GE_LOGIC_NOOP: + srcBlend = BlendFactor::ZERO; + dstBlend = BlendFactor::ONE; + blendEq = BlendEq::ADD; + return true; + + default: + // Let's hope hardware gets it right. + return false; + } } return false; } // Choose the shader part of the above logic op fallback simulation. SimulateLogicOpType SimulateLogicOpShaderTypeIfNeeded() { - if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP) && gstate.isLogicOpEnabled()) { + if (!gstate_c.Use(GPU_USE_LOGIC_OP) && gstate.isLogicOpEnabled()) { switch (gstate.getLogicOp()) { case GE_LOGIC_COPY_INVERTED: case GE_LOGIC_AND_INVERTED: @@ -1039,6 +1070,15 @@ static void ConvertMaskState(GenericMaskState &maskState, bool shaderBitOpsSuppo maskState.channelMask &= ~8; maskState.uniformMask &= ~0xFF000000; } + + // For 5551, only the top alpha bit matters. We might even want to swizzle 4444. + // Alpha should correctly read as 255 from a 5551 texture. + if (gstate.FrameBufFormat() == GE_FORMAT_5551) { + if ((maskState.uniformMask & 0x80000000) != 0) + maskState.uniformMask |= 0xFF000000; + else + maskState.uniformMask &= ~0xFF000000; + } } // Called even if AlphaBlendEnable == false - it also deals with stencil-related blend state. @@ -1243,7 +1283,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl // Some Android devices (especially old Mali, it seems) composite badly if there's alpha in the backbuffer. // So in non-buffered rendering, we will simply consider the dest alpha to be zero in blending equations. #ifdef __ANDROID__ - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { + if (g_Config.bSkipBufferEffects) { if (glBlendFuncA == BlendFactor::DST_ALPHA) glBlendFuncA = BlendFactor::ZERO; if (glBlendFuncB == BlendFactor::DST_ALPHA) glBlendFuncB = BlendFactor::ZERO; if (glBlendFuncA == BlendFactor::ONE_MINUS_DST_ALPHA) glBlendFuncA = BlendFactor::ONE; @@ -1253,7 +1293,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow. BlendEq colorEq; - if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) { + if (gstate_c.Use(GPU_USE_BLEND_MINMAX)) { colorEq = eqLookup[blendFuncEq]; } else { colorEq = eqLookupNoMinMax[blendFuncEq]; @@ -1575,7 +1615,7 @@ void ComputedPipelineState::Convert(bool shaderBitOpsSuppported) { // Passing on the previous applyFramebufferRead as forceFrameBuffer read in the next one, // thus propagating forward. ConvertMaskState(maskState, shaderBitOpsSuppported); - ConvertLogicOpState(logicState, gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead); + ConvertLogicOpState(logicState, gstate_c.Use(GPU_USE_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead); ConvertBlendState(blendState, logicState.applyFramebufferRead); // Note: If the blend state decided it had to use framebuffer reads, @@ -1598,5 +1638,7 @@ void GenericLogicState::ApplyToBlendState(GenericBlendState &blendState) { blendState.dstAlpha = BlendFactor::ZERO; blendState.eqAlpha = BlendEq::ADD; } + logicOpEnabled = false; + logicOp = GE_LOGIC_COPY; } } diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index 038091f7d8..ab524f6c3f 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -56,6 +56,7 @@ bool IsColorTestAgainstZero(); bool IsColorTestTriviallyTrue(); bool IsAlphaTestAgainstZero(); bool NeedsTestDiscard(); +bool IsDepthTestEffectivelyDisabled(); bool IsStencilTestOutputDisabled(); StencilValueType ReplaceAlphaWithStencilType(); diff --git a/GPU/Common/GeometryShaderGenerator.cpp b/GPU/Common/GeometryShaderGenerator.cpp index a814a345da..8c24fa9731 100644 --- a/GPU/Common/GeometryShaderGenerator.cpp +++ b/GPU/Common/GeometryShaderGenerator.cpp @@ -39,18 +39,21 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, std::string *errorString) { - std::vector gl_exts; + std::vector extensions; if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (gl_extensions.EXT_gpu_shader4) { - gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); + extensions.push_back("#extension GL_EXT_gpu_shader4 : enable"); } } bool vertexRangeCulling = !id.Bit(GS_BIT_CURVE); - bool clipClampedDepth = gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP); + + ShaderWriter p(buffer, compat, ShaderStage::Geometry, extensions); + + p.F("// %s\n", GeometryShaderDesc(id).c_str()); - ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts.data(), gl_exts.size()); p.C("layout(triangles) in;\n"); - if (clipClampedDepth && vertexRangeCulling && !gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C("layout(triangle_strip, max_vertices = 12) out;\n"); } else { p.C("layout(triangle_strip, max_vertices = 6) out;\n"); @@ -58,7 +61,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu if (compat.shaderLanguage == GLSL_VULKAN) { WRITE(p, "\n"); - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); } else if (compat.shaderLanguage == HLSL_D3D11) { WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr); } @@ -85,7 +88,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" bool anyInside = false;\n"); } // And apply manual clipping if necessary. - if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { p.C(" float clip0[3];\n"); if (clipClampedDepth) { p.C(" float clip1[3];\n"); @@ -117,10 +120,11 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" }\n"); } - if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // This is basically the same value as gl_ClipDistance would take, z + w. if (vertexRangeCulling) { - p.C(" clip0[i] = projZ * outPos.w + outPos.w;\n"); + // We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.) + p.F(" clip0[i] = projZ * outPos.w + outPos.w + %f;\n", 0.0625 / 65536.0); } else { // Let's not complicate the code overly for this case. We'll clipClampedDepth. p.C(" clip0[i] = 0.0;\n"); @@ -156,7 +160,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.C(" }\n"); } - if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // Clipping against one half-space cuts a triangle (17/27), culls (7/27), or creates two triangles (3/27). // We clip against two, so we can generate up to 4 triangles, a polygon with 6 points. p.C(" int indices[6];\n"); @@ -287,10 +291,11 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix1); } else { // We shouldn't need to worry about rectangles-as-triangles here, since we don't use geometry shaders for that. - p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix0); + // We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.) + p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", clipSuffix0, 0.0625 / 65536.0); } p.C(" gl_Position = outPos;\n"); - if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { } for (size_t i = 0; i < varyings.size(); i++) { diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 2d8529f356..831bc1bf85 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -50,24 +50,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } shaderInfo.clear(); - ShaderInfo off{}; - off.visible = true; - off.name = "Off"; - off.section = "Off"; - for (size_t i = 0; i < ARRAY_SIZE(off.settings); ++i) { - off.settings[i].name.clear(); - off.settings[i].value = 0.0f; - off.settings[i].minValue = -1.0f; - off.settings[i].maxValue = 1.0f; - off.settings[i].step = 0.01f; - } - shaderInfo.push_back(off); - textureShaderInfo.clear(); - TextureShaderInfo textureOff{}; - textureOff.name = "Off"; - textureOff.section = "Off"; - textureShaderInfo.push_back(textureOff); auto appendShader = [&](const ShaderInfo &info) { auto beginErase = std::remove(shaderInfo.begin(), shaderInfo.end(), info.name); @@ -154,9 +137,11 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct continue; } - if (section.Exists("Fragment") && section.Exists("Vertex") && strncasecmp(shaderType.c_str(), "render", shaderType.size()) == 0) { + if (section.Exists("Fragment") && section.Exists("Vertex") && + (strncasecmp(shaderType.c_str(), "render", shaderType.size()) == 0 || + strncasecmp(shaderType.c_str(), "StereoToMono", shaderType.size()) == 0)) { // Valid shader! - ShaderInfo info; + ShaderInfo info{}; std::string temp; info.section = section.name(); @@ -176,6 +161,12 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct if (info.parent == "Off") info.parent.clear(); + if (strncasecmp(shaderType.c_str(), "stereotomono", shaderType.size()) == 0) { + info.isStereo = true; + info.isUpscalingFilter = false; + info.parent.clear(); + } + for (size_t i = 0; i < ARRAY_SIZE(info.settings); ++i) { auto &setting = info.settings[i]; section.Get(StringFromFormat("SettingName%d", i + 1).c_str(), &setting.name, ""); @@ -183,12 +174,6 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct section.Get(StringFromFormat("SettingMinValue%d", i + 1).c_str(), &setting.minValue, -1.0f); section.Get(StringFromFormat("SettingMaxValue%d", i + 1).c_str(), &setting.maxValue, 1.0f); section.Get(StringFromFormat("SettingStep%d", i + 1).c_str(), &setting.step, 0.01f); - - // Populate the default setting value. - std::string section = StringFromFormat("%sSettingValue%d", info.section.c_str(), i + 1); - if (!setting.name.empty() && g_Config.mPostShaderSetting.find(section) == g_Config.mPostShaderSetting.end()) { - g_Config.mPostShaderSetting.emplace(section, setting.value); - } } // Let's ignore shaders we can't support. TODO: Not a very good check @@ -206,7 +191,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct } } else if (section.Exists("Compute") && strncasecmp(shaderType.c_str(), "texture", shaderType.size()) == 0) { // This is a texture shader. - TextureShaderInfo info; + TextureShaderInfo info{}; std::string temp; info.section = section.name(); section.Get("Name", &info.name, section.name().c_str()); @@ -216,11 +201,35 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct if (info.scaleFactor >= 2 && info.scaleFactor < 8) { appendTextureShader(info); } + } else if (!section.name().empty()) { + WARN_LOG(G3D, "Unrecognized shader type '%s' or invalid shader in section '%s'", shaderType.c_str(), section.name().c_str()); } } } } + // Sort shaders alphabetically. + std::sort(shaderInfo.begin(), shaderInfo.end()); + std::sort(textureShaderInfo.begin(), textureShaderInfo.end()); + + ShaderInfo off{}; + off.visible = true; + off.name = "Off"; + off.section = "Off"; + for (size_t i = 0; i < ARRAY_SIZE(off.settings); ++i) { + off.settings[i].name.clear(); + off.settings[i].value = 0.0f; + off.settings[i].minValue = -1.0f; + off.settings[i].maxValue = 1.0f; + off.settings[i].step = 0.01f; + } + shaderInfo.insert(shaderInfo.begin(), off); + + TextureShaderInfo textureOff{}; + textureOff.name = "Off"; + textureOff.section = "Off"; + textureShaderInfo.insert(textureShaderInfo.begin(), textureOff); + // We always want the not visible ones at the end. Makes menus easier. for (const auto &info : notVisible) { appendShader(info); @@ -235,6 +244,16 @@ void ReloadAllPostShaderInfo(Draw::DrawContext *draw) { LoadPostShaderInfo(draw, directories); } +void RemoveUnknownPostShaders(std::vector *names) { + for (auto iter = names->begin(); iter != names->end(); ) { + if (GetPostShaderInfo(*iter) == nullptr) { + iter = names->erase(iter); + } else { + ++iter; + } + } +} + const ShaderInfo *GetPostShaderInfo(const std::string &name) { for (size_t i = 0; i < shaderInfo.size(); i++) { if (shaderInfo[i].section == name) @@ -299,3 +318,25 @@ const TextureShaderInfo *GetTextureShaderInfo(const std::string &name) { const std::vector &GetAllTextureShaderInfo() { return textureShaderInfo; } + +void FixPostShaderOrder(std::vector *names) { + // There's one rule only that we enforce - only one shader can use UsePreviousFrame, + // and it has to be the last one. So we simply remove any we find from the list, + // and then append it to the end if there is one. + std::string prevFrameShader; + for (auto iter = names->begin(); iter != names->end(); ) { + const ShaderInfo *info = GetPostShaderInfo(*iter); + if (info) { + if (info->usePreviousFrame) { + prevFrameShader = *iter; + iter = names->erase(iter++); + continue; + } + } + ++iter; + } + + if (!prevFrameShader.empty()) { + names->push_back(prevFrameShader); + } +} diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 5226638078..882290d49f 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -19,11 +19,11 @@ // Postprocessing shader manager // For FXAA, "Natural", bloom, B&W, cross processing and whatnot. +#pragma once + #include #include -#include "Common/Data/Format/IniFile.h" - struct ShaderInfo { Path iniFile; // which ini file was this definition in? So we can write settings back later std::string section; // ini file section. This is saved. @@ -39,6 +39,8 @@ struct ShaderInfo { bool outputResolution; // Use x1 rendering res + nearest screen scaling filter bool isUpscalingFilter; + // Is used to post-process stereo-rendering to mono, like red/blue. + bool isStereo; // Use 2x display resolution for supersampling with blurry shaders. int SSAAFilterLevel; // Force constant/max refresh for animated filters @@ -58,12 +60,21 @@ struct ShaderInfo { // TODO: Add support for all kinds of fun options like mapping the depth buffer, // SRGB texture reads, etc. prev shader? - bool operator == (const std::string &other) { + bool operator == (const std::string &other) const { return name == other; } - bool operator == (const ShaderInfo &other) { + bool operator == (const ShaderInfo &other) const { return name == other.name; } + + bool operator < (const ShaderInfo &other) const { + if (name < other.name) return true; + if (name > other.name) return false; + // Tie breaker + if (iniFile < other.iniFile) return true; + if (iniFile > other.iniFile) return false; + return false; + } }; struct TextureShaderInfo { @@ -76,12 +87,21 @@ struct TextureShaderInfo { // Upscaling shaders have a fixed scale factor. int scaleFactor; - bool operator == (const std::string &other) { + bool operator == (const std::string &other) const { return name == other; } - bool operator == (const TextureShaderInfo &other) { + bool operator == (const TextureShaderInfo &other) const { return name == other.name; } + + bool operator < (const TextureShaderInfo &other) const { + if (name < other.name) return true; + if (name > other.name) return false; + // Tie breaker + if (iniFile < other.iniFile) return true; + if (iniFile > other.iniFile) return false; + return false; + } }; void ReloadAllPostShaderInfo(Draw::DrawContext *draw); @@ -94,3 +114,9 @@ const std::vector &GetAllPostShaderInfo(); const TextureShaderInfo *GetTextureShaderInfo(const std::string &name); const std::vector &GetAllTextureShaderInfo(); +void RemoveUnknownPostShaders(std::vector *names); + +// Call this any time you alter the postshader list. It makes sure +// that "usePrevFrame" shaders are at the end, and that there's only one. +// It'll also enforce any similar future rules. +void FixPostShaderOrder(std::vector *names); diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index e430374079..4341961214 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -34,6 +34,7 @@ #include "Core/HW/Display.h" #include "GPU/Common/PostShader.h" #include "GPU/Common/PresentationCommon.h" +#include "GPU/GPUState.h" #include "Common/GPU/ShaderTranslation.h" struct Vertex { @@ -74,77 +75,67 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f bool rotated = rotation == ROTATION_LOCKED_VERTICAL || rotation == ROTATION_LOCKED_VERTICAL180; - if (IsVRBuild()) { - if (IsFlatVRScene()) { - g_Config.iSmallDisplayZoomType = (int)SmallDisplayZoom::AUTO; - } else { - g_Config.iSmallDisplayZoomType = (int)SmallDisplayZoom::STRETCH; + bool stretch = g_Config.bDisplayStretch; + + float offsetX = g_Config.fDisplayOffsetX; + float offsetY = g_Config.fDisplayOffsetY; + if (GetGPUBackend() != GPUBackend::VULKAN) { + offsetY = 1.0 - offsetY; + } + + float scale = g_Config.fDisplayScale; + float aspectRatioAdjust = g_Config.fDisplayAspectRatio; + + // Ye olde 1080p hack, new version: If everything is setup to exactly cover the screen (defaults), and the screen display aspect ratio is 16:9, + // stretch the PSP's aspect ratio veeery slightly to fill it completely. + if (scale == 1.0f && offsetX == 0.5f && offsetY == 0.5f && aspectRatioAdjust == 1.0f) { + if (fabsf(frame.w / frame.h - 16.0f / 9.0f) < 0.0001f) { + aspectRatioAdjust = (frame.w / frame.h) / (480.0f / 272.0f); } } - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::STRETCH) { + float origRatio = !rotated ? origW / origH : origH / origW; + float frameRatio = frame.w / frame.h; + + if (stretch) { + // Automatically set aspect ratio to match the display, IF the rotation matches the output display ratio! Otherwise, just + // sets standard aspect ratio because actually stretching will just look silly. + bool globalRotated = g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270; + if (rotated == dp_yres > dp_xres) { + origRatio = frameRatio; + } else { + origRatio *= aspectRatioAdjust; + } + } else { + origRatio *= aspectRatioAdjust; + } + + float scaledWidth = frame.w * scale; + float scaledHeight = frame.h * scale; + + if (origRatio > frameRatio) { + // Image is wider than frame. Center vertically. + outW = scaledWidth; + outH = scaledWidth / origRatio; + } else { + // Image is taller than frame. Center horizontally. + outW = scaledHeight * origRatio; + outH = scaledHeight; + } + + if (IsVREnabled()) { + rc->x = 0; + rc->y = 0; + rc->w = floorf(frame.w); + rc->h = floorf(frame.h); outW = frame.w; outH = frame.h; } else { - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::MANUAL) { - float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frame.w + frame.x; - float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frame.h + frame.y; - // Have to invert Y for GL - if (GetGPUBackend() == GPUBackend::OPENGL) { - offsetY = offsetY * -1.0f; - } - float customZoom = g_Config.fSmallDisplayZoomLevel; - float smallDisplayW = origW * customZoom; - float smallDisplayH = origH * customZoom; - if (!rotated) { - rc->x = floorf(((frame.w - smallDisplayW) / 2.0f) + offsetX); - rc->y = floorf(((frame.h - smallDisplayH) / 2.0f) + offsetY); - rc->w = floorf(smallDisplayW); - rc->h = floorf(smallDisplayH); - return; - } else { - rc->x = floorf(((frame.w - smallDisplayH) / 2.0f) + offsetX); - rc->y = floorf(((frame.h - smallDisplayW) / 2.0f) + offsetY); - rc->w = floorf(smallDisplayH); - rc->h = floorf(smallDisplayW); - return; - } - } else if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - // Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.) - float pixelCrop = frame.h / 270.0f; - float resCommonWidescreen = pixelCrop - floor(pixelCrop); - if (!rotated && resCommonWidescreen == 0.0f && frame.w >= pixelCrop * 480.0f) { - rc->x = floorf((frame.w - pixelCrop * 480.0f) * 0.5f + frame.x); - rc->y = floorf(-pixelCrop + frame.y); - rc->w = floorf(pixelCrop * 480.0f); - rc->h = floorf(pixelCrop * 272.0f); - return; - } - } - - float origRatio = !rotated ? origW / origH : origH / origW; - float frameRatio = frame.w / frame.h; - - if (origRatio > frameRatio) { - // Image is wider than frame. Center vertically. - outW = frame.w; - outH = frame.w / origRatio; - // Stretch a little bit - if (!rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) - outH = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 - } else { - // Image is taller than frame. Center horizontally. - outW = frame.h * origRatio; - outH = frame.h; - if (rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) - outW = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 - } + rc->x = floorf(frame.x + frame.w * offsetX - outW * 0.5f); + rc->y = floorf(frame.y + frame.h * offsetY - outH * 0.5f); + rc->w = floorf(outW); + rc->h = floorf(outH); } - - rc->x = floorf((frame.w - outW) / 2.0f + frame.x); - rc->y = floorf((frame.h - outH) / 2.0f + frame.y); - rc->w = floorf(outW); - rc->h = floorf(outH); } PresentationCommon::PresentationCommon(Draw::DrawContext *draw) : draw_(draw) { @@ -155,7 +146,7 @@ PresentationCommon::~PresentationCommon() { DestroyDeviceObjects(); } -void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) { +void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) const { if (!g_Config.bEnableCardboardVR) { cardboardSettings->enabled = false; return; @@ -181,7 +172,15 @@ void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettin cardboardSettings->screenHeight = cardboardScreenHeight; } -void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) { +static float GetShaderSettingValue(const ShaderInfo *shaderInfo, int i, const char *nameSuffix) { + std::string key = shaderInfo->section + nameSuffix; + auto it = g_Config.mPostShaderSetting.find(key); + if (it != g_Config.mPostShaderSetting.end()) + return it->second; + return shaderInfo->settings[i].value; +} + +void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) const { float u_delta = 1.0f / bufferWidth; float v_delta = 1.0f / bufferHeight; float u_pixel_delta = 1.0f / targetWidth; @@ -205,10 +204,10 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f; uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f; - uniforms->setting[0] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue1"];; - uniforms->setting[1] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue2"]; - uniforms->setting[2] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue3"]; - uniforms->setting[3] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue4"]; + uniforms->setting[0] = GetShaderSettingValue(shaderInfo, 0, "SettingCurrentValue1"); + uniforms->setting[1] = GetShaderSettingValue(shaderInfo, 1, "SettingCurrentValue2"); + uniforms->setting[2] = GetShaderSettingValue(shaderInfo, 2, "SettingCurrentValue3"); + uniforms->setting[3] = GetShaderSettingValue(shaderInfo, 3, "SettingCurrentValue4"); } static std::string ReadShaderSrc(const Path &filename) { @@ -224,7 +223,22 @@ static std::string ReadShaderSrc(const Path &filename) { } // Note: called on resize and settings changes. +// Also takes care of making sure the appropriate stereo shader is compiled. bool PresentationCommon::UpdatePostShader() { + DestroyStereoShader(); + + if (gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE)) { + const ShaderInfo *stereoShaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); + if (stereoShaderInfo) { + bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); + if (result) { + stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); + } + } else { + WARN_LOG(G3D, "Failed to get info about stereo shader '%s'", g_Config.sStereoToMonoShader.c_str()); + } + } + std::vector shaderInfo; if (!g_Config.vPostShaderNames.empty()) { ReloadAllPostShaderInfo(draw_); @@ -232,17 +246,23 @@ bool PresentationCommon::UpdatePostShader() { } DestroyPostShader(); - if (shaderInfo.empty()) + if (shaderInfo.empty()) { + usePostShader_ = false; return false; + } bool usePreviousFrame = false; bool usePreviousAtOutputResolution = false; for (size_t i = 0; i < shaderInfo.size(); ++i) { const ShaderInfo *next = i + 1 < shaderInfo.size() ? shaderInfo[i + 1] : nullptr; - if (!BuildPostShader(shaderInfo[i], next)) { + Draw::Pipeline *postPipeline = nullptr; + if (!BuildPostShader(shaderInfo[i], next, &postPipeline)) { DestroyPostShader(); return false; } + _dbg_assert_(postPipeline); + postShaderPipelines_.push_back(postPipeline); + postShaderInfo_.push_back(*shaderInfo[i]); if (shaderInfo[i]->usePreviousFrame) { usePreviousFrame = true; usePreviousAtOutputResolution = shaderInfo[i]->outputResolution; @@ -258,7 +278,7 @@ bool PresentationCommon::UpdatePostShader() { previousIndex_ = 0; for (int i = 0; i < FRAMES; ++i) { - previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, false, "inter_presentation" }); + previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, 0, false, "inter_presentation" }); if (!previousFramebuffers_[i]) { DestroyPostShader(); return false; @@ -270,7 +290,9 @@ bool PresentationCommon::UpdatePostShader() { return true; } -bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next) { +bool PresentationCommon::CompilePostShader(const ShaderInfo *shaderInfo, Draw::Pipeline **outPipeline) const { + _assert_(shaderInfo); + std::string vsSourceGLSL = ReadShaderSrc(shaderInfo->vertexShaderFile); std::string fsSourceGLSL = ReadShaderSrc(shaderInfo->fragmentShaderFile); if (vsSourceGLSL.empty() || fsSourceGLSL.empty()) { @@ -305,9 +327,22 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha } }; Draw::Pipeline *pipeline = CreatePipeline({ vs, fs }, true, &postShaderDesc); + + fs->Release(); + vs->Release(); + if (!pipeline) return false; + *outPipeline = pipeline; + return true; +} + +bool PresentationCommon::BuildPostShader(const ShaderInfo * shaderInfo, const ShaderInfo * next, Draw::Pipeline **outPipeline) { + if (!CompilePostShader(shaderInfo, outPipeline)) { + return false; + } + if (!shaderInfo->outputResolution || next) { int nextWidth = renderWidth_; int nextHeight = renderHeight_; @@ -335,13 +370,12 @@ bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const Sha } if (!AllocateFramebuffer(nextWidth, nextHeight)) { - pipeline->Release(); + (*outPipeline)->Release(); + *outPipeline = nullptr; return false; } } - postShaderPipelines_.push_back(pipeline); - postShaderInfo_.push_back(*shaderInfo); return true; } @@ -360,7 +394,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) { } // No depth/stencil for post processing - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, "presentation" }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, 0, false, "presentation" }); if (!fbo) { return false; } @@ -410,7 +444,7 @@ void PresentationCommon::DeviceRestore(Draw::DrawContext *draw) { CreateDeviceObjects(); } -Draw::Pipeline *PresentationCommon::CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc) { +Draw::Pipeline *PresentationCommon::CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc) const { using namespace Draw; Semantic pos = SEM_POSITION; @@ -497,12 +531,12 @@ void PresentationCommon::DestroyDeviceObjects() { restorePostShader_ = usePostShader_; DestroyPostShader(); + DestroyStereoShader(); } void PresentationCommon::DestroyPostShader() { usePostShader_ = false; - DoReleaseVector(postShaderModules_); DoReleaseVector(postShaderPipelines_); DoReleaseVector(postShaderFramebuffers_); DoReleaseVector(previousFramebuffers_); @@ -510,7 +544,13 @@ void PresentationCommon::DestroyPostShader() { postShaderFBOUsage_.clear(); } -Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) { +void PresentationCommon::DestroyStereoShader() { + DoRelease(stereoPipeline_); + delete stereoShaderInfo_; + stereoShaderInfo_ = nullptr; +} + +Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) const { std::string translated = src; if (lang != lang_) { // Gonna have to upconvert the shader. @@ -519,10 +559,7 @@ Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, S return nullptr; } } - Draw::ShaderModule *shader = draw_->CreateShaderModule(stage, lang_, (const uint8_t *)translated.c_str(), translated.size(), "postshader"); - if (shader) - postShaderModules_.push_back(shader); return shader; } @@ -546,13 +583,28 @@ void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidt srcHeight_ = bufferHeight; } -void PresentationCommon::BindSource(int binding) { +// Return value is if stereo binding succeeded. +bool PresentationCommon::BindSource(int binding, bool bindStereo) { if (srcTexture_) { draw_->BindTexture(binding, srcTexture_); + return false; } else if (srcFramebuffer_) { - draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + if (bindStereo) { + if (srcFramebuffer_->Layers() > 1) { + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); + return true; + } else { + // Single layer. This might be from a post shader and those don't yet support stereo. + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + return false; + } + } else { + draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0); + return false; + } } else { _assert_(false); + return false; } } @@ -561,14 +613,16 @@ void PresentationCommon::UpdateUniforms(bool hasVideo) { } void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); // TODO: If shader objects have been created by now, we might have received errors. // GLES can have the shader fail later, shader->failed / shader->error. // This should auto-disable usePostShader_ and call ShowPostShaderError(). bool useNearest = flags & OutputFlags::NEAREST; - const bool usePostShader = usePostShader_ && !(flags & OutputFlags::RB_SWIZZLE); + bool useStereo = gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE) && stereoPipeline_ != nullptr; // TODO: Also check that the backend has support for it. + + const bool usePostShader = usePostShader_ && !useStereo && !(flags & OutputFlags::RB_SWIZZLE); const bool isFinalAtOutputResolution = usePostShader && postShaderFramebuffers_.size() < postShaderPipelines_.size(); Draw::Framebuffer *postShaderOutput = nullptr; int lastWidth = srcWidth_; @@ -643,7 +697,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u } } - if (isFinalAtOutputResolution) { + if (isFinalAtOutputResolution || useStereo) { // In this mode, we ignore the g_display_rot_matrix. Apply manually. if (g_display_rotation != DisplayRotation::ROTATE_0) { for (int i = 0; i < 4; i++) { @@ -671,9 +725,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u if (postShaderOutput) { draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); } else { - BindSource(0); + BindSource(0, false); } - BindSource(1); + BindSource(1, false); if (shaderInfo->usePreviousFrame) draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT, 0); @@ -752,26 +806,38 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline); } - Draw::Pipeline *pipeline = (flags & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_; - if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { - pipeline = postShaderPipelines_.back(); - } - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit"); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); - draw_->BindPipeline(pipeline); + Draw::Pipeline *pipeline = (flags & OutputFlags::RB_SWIZZLE) ? texColorRBSwizzle_ : texColor_; - if (postShaderOutput) { - draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); + if (useStereo) { + draw_->BindPipeline(stereoPipeline_); + if (!BindSource(0, true)) { + // Fall back + draw_->BindPipeline(texColor_); + useStereo = false; // Otherwise we end up uploading the wrong uniforms + } } else { - BindSource(0); + if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { + pipeline = postShaderPipelines_.back(); + } + + draw_->BindPipeline(pipeline); + if (postShaderOutput) { + draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0); + } else { + BindSource(0, false); + } } - BindSource(1); + BindSource(1, false); if (isFinalAtOutputResolution && previousFramebuffers_.empty()) { CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, &postShaderInfo_.back(), &uniforms); draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms)); + } else if (useStereo) { + CalculatePostShaderUniforms(lastWidth, lastHeight, (int)rc.w, (int)rc.h, stereoShaderInfo_, &uniforms); + draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms)); } else { Draw::VsTexColUB ub{}; memcpy(ub.WorldViewProj, g_display_rot_matrix.m, sizeof(float) * 16); @@ -793,6 +859,8 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u CardboardSettings cardboardSettings; GetCardboardSettings(&cardboardSettings); if (cardboardSettings.enabled) { + // TODO: This could actually support stereo now, with an appropriate shader. + // This is what the left eye sees. setViewport(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); draw_->DrawIndexed(6, 0); @@ -809,16 +877,18 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u DoRelease(srcTexture_); // Unbinds all textures and samplers too, needed since sometimes a MakePixelTexture is deleted etc. - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); previousUniforms_ = uniforms; } -void PresentationCommon::CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) { +void PresentationCommon::CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) const { // Check if postprocessing shader is doing upscaling as it requires native resolution std::vector shaderInfo; if (!g_Config.vPostShaderNames.empty()) { ReloadAllPostShaderInfo(draw_); + RemoveUnknownPostShaders(&g_Config.vPostShaderNames); + FixPostShaderOrder(&g_Config.vPostShaderNames); shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } @@ -854,7 +924,10 @@ void PresentationCommon::CalculateRenderResolution(int *width, int *height, int } } - if (g_Config.IsPortrait()) { + if (IsVREnabled()) { + *width = 480 * zoom; + *height = 480 * zoom; + } else if (g_Config.IsPortrait()) { *width = 272 * zoom; *height = 480 * zoom; } else { diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 7ce81117b8..981c707b05 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -78,9 +78,11 @@ public: PresentationCommon(Draw::DrawContext *draw); ~PresentationCommon(); - void UpdateSize(int w, int h, int rw, int rh) { + void UpdateDisplaySize(int w, int h) { pixelWidth_ = w; pixelHeight_ = h; + } + void UpdateRenderSize(int rw, int rh) { renderWidth_ = rw; renderHeight_ = rh; } @@ -102,24 +104,27 @@ public: void SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight); void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1); - void CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa); + void CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) const; protected: void CreateDeviceObjects(); void DestroyDeviceObjects(); + void DestroyPostShader(); + void DestroyStereoShader(); - void ShowPostShaderError(const std::string &errorString); + static void ShowPostShaderError(const std::string &errorString); - Draw::ShaderModule *CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString); - Draw::Pipeline *CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc); - bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next); + Draw::ShaderModule *CompileShaderModule(ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) const; + Draw::Pipeline *CreatePipeline(std::vector shaders, bool postShader, const UniformBufferDesc *uniformDesc) const; + bool CompilePostShader(const ShaderInfo *shaderInfo, Draw::Pipeline **outPipeline) const; + bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next, Draw::Pipeline **outPipeline); bool AllocateFramebuffer(int w, int h); - void BindSource(int binding); + bool BindSource(int binding, bool bindStereo); - void GetCardboardSettings(CardboardSettings *cardboardSettings); - void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms); + void GetCardboardSettings(CardboardSettings *cardboardSettings) const; + void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) const; Draw::DrawContext *draw_; Draw::Pipeline *texColor_ = nullptr; @@ -129,11 +134,14 @@ protected: Draw::Buffer *vdata_ = nullptr; Draw::Buffer *idata_ = nullptr; - std::vector postShaderModules_; std::vector postShaderPipelines_; std::vector postShaderFramebuffers_; std::vector postShaderInfo_; std::vector previousFramebuffers_; + + Draw::Pipeline *stereoPipeline_ = nullptr; + ShaderInfo *stereoShaderInfo_ = nullptr; + int previousIndex_ = 0; PostShaderUniforms previousUniforms_{}; diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index 09f2552a9b..ccb58c1c9b 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -14,14 +14,13 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { "tex" } + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN } }; // Requires full size integer math. It would be possible to make a floating point-only version with lots of // modulo and stuff, might do it one day. Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to) { writer.HighPrecisionFloat(); - writer.DeclareSamplers(samplers); if (writer.Lang().bitwiseOps) { @@ -161,7 +160,7 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf } } - writer.BeginFSMain(g_draw2Duniforms, varyings, FSFLAG_NONE); + writer.BeginFSMain(g_draw2Duniforms, varyings); if (IsBufferFormat16Bit(from) && IsBufferFormat16Bit(to)) { writer.C(" vec4 val = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); @@ -182,7 +181,7 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf writer.C(" vec4 outColor = unpackColor(u == 0.0 ? packColor(val.rg) : packColor(val.ba));\n"); } - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); return Draw2DPipelineInfo{ "reinterpret", diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 43fcbab8ab..cb9b10af75 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -62,10 +62,12 @@ std::string VertexShaderDesc(const VShaderID &id) { if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN "; if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "Cull "; + if (id.Bit(VS_BIT_SIMPLE_STEREO)) desc << "SimpleStereo "; + return desc.str(); } -void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { +void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) { bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0; bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP); @@ -83,7 +85,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, } bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough && !gstate.isModeClear(); - bool vertexRangeCulling = gstate_c.Supports(GPU_SUPPORTS_VS_RANGE_CULLING) && + bool vertexRangeCulling = gstate_c.Use(GPU_USE_VS_RANGE_CULLING) && !isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692 VShaderID id; @@ -92,6 +94,10 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, id.SetBit(VS_BIT_HAS_COLOR, hasColor); id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling); + if (!isModeThrough && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + id.SetBit(VS_BIT_SIMPLE_STEREO); + } + if (doTexture) { id.SetBit(VS_BIT_DO_TEXTURE); @@ -112,7 +118,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, } // Bones. - bool enableBones = vertTypeIsSkinningEnabled(vertType); + bool enableBones = !useSkinInDecode && vertTypeIsSkinningEnabled(vertType); id.SetBit(VS_BIT_ENABLE_BONES, enableBones); if (enableBones) { id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1); @@ -124,7 +130,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, if (gstate.isLightingEnabled()) { // doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping. id.SetBit(VS_BIT_LIGHTING_ENABLE); - if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) { id.SetBit(VS_BIT_LIGHT_UBERSHADER); } else { id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate()); @@ -167,8 +173,9 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" }; -static bool MatrixNeedsProjection(const float m[12]) { - return m[2] != 0.0f || m[5] != 0.0f || m[8] != 0.0f || m[11] != 1.0f; +static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) { + // For GE_PROJMAP_UV, we can ignore m[8] since it multiplies to zero. + return m[2] != 0.0f || m[5] != 0.0f || (m[8] != 0.0f && mode != GE_PROJMAP_UV) || m[11] != 1.0f; } std::string FragmentShaderDesc(const FShaderID &id) { @@ -250,8 +257,10 @@ std::string FragmentShaderDesc(const FShaderID &id) { else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero "; if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround "; - if (id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) desc << "ReplaceLogic "; - + if ((id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "ReplaceLogic "; + if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray "; + if (id.Bit(FS_BIT_STEREO)) desc << "Stereo "; + if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc << "(fetch)"; return desc.str(); } @@ -275,7 +284,7 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue(); bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue(); bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled(); - bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix)); + bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix, gstate.getUVProjMode())); bool doTextureAlpha = gstate.isTextureAlphaUsed(); bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT; @@ -359,15 +368,32 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip id.SetBits(FS_BIT_BLENDFUNC_B, 4, gstate.getBlendFuncB()); } id.SetBit(FS_BIT_FLATSHADE, doFlatShading); - id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask); + // All framebuffers are array textures in Vulkan now. + if (gstate_c.arrayTexture && g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { + id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE); + } + + // Stereo support + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + id.SetBit(FS_BIT_STEREO); + } + if (g_Config.bVendorBugChecksEnabled && bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { bool stencilWithoutDepth = !IsStencilTestOutputDisabled() && (!gstate.isDepthTestEnabled() || !gstate.isDepthWriteEnabled()); if (stencilWithoutDepth) { id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, stencilWithoutDepth); } } + + // In case the USE flag changes (for example, in multisampling we might disable input attachments), + // we don't want to accidentally use the wrong cached shader here. So moved it to a bit. + if (FragmentIdNeedsFramebufferRead(id)) { + if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) { + id.SetBit(FS_BIT_USE_FRAMEBUFFER_FETCH); + } + } } *id_out = id; @@ -390,11 +416,11 @@ void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim bool isTriangle = prim == GE_PRIM_TRIANGLES || prim == GE_PRIM_TRIANGLE_FAN || prim == GE_PRIM_TRIANGLE_STRIP; bool vertexRangeCulling = !isCurve; - bool clipClampedDepth = gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP) && !gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !gstate_c.Use(GPU_USE_CLIP_DISTANCE); // If we're not using GS culling, return a zero ID. // Also, only use this for triangle primitives. - if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle || !gstate_c.Supports(GPU_SUPPORTS_GS_CULLING)) { + if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle || !gstate_c.Use(GPU_USE_GS_CULLING)) { *id_out = id; return; } diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 2edf271b6d..6c3a886669 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -15,7 +15,7 @@ enum VShaderBit : uint8_t { VS_BIT_HAS_COLOR = 3, VS_BIT_DO_TEXTURE = 4, VS_BIT_VERTEX_RANGE_CULLING = 5, - // 6 is free, + VS_BIT_SIMPLE_STEREO = 6, // 7 is free. VS_BIT_USE_HW_TRANSFORM = 8, VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform @@ -98,6 +98,9 @@ enum FShaderBit : uint8_t { FS_BIT_COLOR_WRITEMASK = 50, FS_BIT_REPLACE_LOGIC_OP = 51, // 4 bits. GE_LOGIC_COPY means no-op/off. FS_BIT_SHADER_DEPAL_MODE = 55, // 2 bits (ShaderDepalMode) + FS_BIT_SAMPLE_ARRAY_TEXTURE = 57, // For multiview, framebuffers are array textures and we need to sample the two layers correctly. + FS_BIT_STEREO = 58, + FS_BIT_USE_FRAMEBUFFER_FETCH = 59, }; static inline FShaderBit operator +(FShaderBit bit, int i) { @@ -273,7 +276,7 @@ namespace Draw { class Bugs; } -void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); +void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode); // Generates a compact string that describes the shader. Useful in a list to get an overview // of the current flora of shaders. std::string VertexShaderDesc(const VShaderID &id); diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 3c56d833e5..724fd26080 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -72,6 +72,10 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo maxValues[3] = NAN; } +void FrameUpdateUniforms(UB_Frame *ub, bool useBufferedRendering) { + ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation; +} + void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat3(ub->texEnvColor, gstate.texenvcolor); @@ -139,7 +143,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView flippedMatrix = flippedMatrix * g_display_rot_matrix; } CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); - ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation; } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { @@ -160,7 +163,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); - ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation; } // Transform diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index c746179316..ecddc4b3ca 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -27,7 +27,6 @@ struct alignas(16) UB_VS_FS_Base { float tex[12]; float uvScaleOffset[4]; float depthRange[4]; - // Rotation is used only for software transform. float matAmbient[4]; float cullRangeMin[4]; float cullRangeMax[4]; @@ -37,7 +36,7 @@ struct alignas(16) UB_VS_FS_Base { float fogColor[3]; uint32_t alphaColorRef; float texEnvColor[3]; uint32_t colorTestMask; float blendFixA[3]; float stencil; - float blendFixB[3]; float rotation; + float blendFixB[3]; float padUnused; float texClamp[4]; float texClampOffset[2]; float fogCoef[2]; // VR stuff is to go here, later. For normal drawing, we can then get away @@ -62,7 +61,7 @@ R"( mat4 u_proj; vec3 u_fogcolor; uint u_alphacolorref; vec3 u_texenv; uint u_alphacolormask; vec3 u_blendFixA; float u_stencilReplaceValue; - vec3 u_blendFixB; float u_rotation; + vec3 u_blendFixB; float u_padUnused; vec4 u_texclamp; vec2 u_texclampoff; vec2 u_fogcoef; @@ -131,10 +130,22 @@ static const char * const ub_vs_bonesStr = R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bone4; mat3x4 u_bone5; mat3x4 u_bone6; mat3x4 u_bone7; mat3x4 u_bone8; )"; + +static const char * const ub_frameStr = +R"( + float u_rotation; +)"; + +// Frame-global uniforms. +struct UB_Frame { + float rotation; // This is only used when using software transform, and non-buffered, to support native screen rotation. +}; + void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ); void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering); void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms); void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms); +void FrameUpdateUniforms(UB_Frame *ub, bool useBufferedRendering); uint32_t PackLightControlBits(); diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 5e3c0c5850..28cdef056e 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -149,7 +149,7 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) { return 0; } -void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) { +void SoftwareTransform::SetProjMatrix(const float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) { memcpy(&projMatrix_.m, mtx, 16 * sizeof(float)); if (invertedY) { @@ -168,29 +168,6 @@ void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invert projMatrix_.translateAndScale(trans, scale); } -static void ReadWeightedNormal(Vec3f &source, VertexReader &reader, u32 vertType, bool skinningEnabled) { - if (reader.hasNormal()) - reader.ReadNrm(source.AsArray()); - if (skinningEnabled) { - float weights[8]; - reader.ReadWeights(weights); - - // Have to recalculate this, unfortunately. Please use software skinning... - Vec3f nsum(0, 0, 0); - for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) { - if (weights[i] != 0.0f) { - Vec3f norm; - Norm3ByMatrix43(norm.AsArray(), source.AsArray(), gstate.boneMatrix + i * 12); - nsum += norm * weights[i]; - } - } - - source = nsum; - } - if (gstate.areNormalsReversed()) - source = -source; -} - void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result) { u8 *decoded = params_.decoded; TransformedVertex *transformed = params_.transformed; @@ -204,8 +181,6 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt vscale /= gstate_c.curTextureHeight; } - bool skinningEnabled = vertTypeIsSkinningEnabled(vertType); - const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); float widthFactor = (float) w / (float) gstate_c.curTextureWidth; @@ -230,6 +205,9 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt VertexReader reader(decoded, decVtxFormat, vertType); if (throughmode) { + const u32 materialAmbientRGBA = gstate.getMaterialAmbientRGBA(); + const bool hasColor = reader.hasColor0(); + const bool hasUV = reader.hasUV(); for (int index = 0; index < maxIndex; index++) { // Do not touch the coordinates or the colors. No lighting. reader.Goto(index); @@ -238,19 +216,19 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt reader.ReadPos(vert.pos); vert.pos_w = 1.0f; - if (reader.hasColor0()) { + if (hasColor) { if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) { reader.Goto(index + provokeIndOffset); - reader.ReadColor0_8888(vert.color0); + vert.color0_32 = reader.ReadColor0_8888(); reader.Goto(index); } else { - reader.ReadColor0_8888(vert.color0); + vert.color0_32 = reader.ReadColor0_8888(); } } else { - vert.color0_32 = gstate.getMaterialAmbientRGBA(); + vert.color0_32 = materialAmbientRGBA; } - if (reader.hasUV()) { + if (hasUV) { reader.ReadUV(vert.uv); vert.u *= uscale; @@ -265,6 +243,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt // The w of uv is also never used (hardcoded to 1.0.) } } else { + const Vec4f materialAmbientRGBA = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); // Okay, need to actually perform the full transform. for (int index = 0; index < maxIndex; index++) { reader.Goto(index); @@ -292,51 +271,17 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt if (reader.hasColor0()) reader.ReadColor0(unlitColor.AsArray()); else - unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); + unlitColor = materialAmbientRGBA; if (reader.hasNormal()) reader.ReadNrm(normal.AsArray()); - if (!skinningEnabled) { - Vec3ByMatrix43(out, pos, gstate.worldMatrix); - if (reader.hasNormal()) { - if (gstate.areNormalsReversed()) { - normal = -normal; - } - Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); - worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1); - } - } else { - float weights[8]; - // For flat, we need the vertex weights. - reader.Goto(index); - reader.ReadWeights(weights); - - // Skinning - Vec3f psum(0, 0, 0); - Vec3f nsum(0, 0, 0); - for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) { - if (weights[i] != 0.0f) { - Vec3ByMatrix43(out, pos, gstate.boneMatrix+i*12); - Vec3f tpos(out); - psum += tpos * weights[i]; - if (reader.hasNormal()) { - Vec3f norm; - Norm3ByMatrix43(norm.AsArray(), normal.AsArray(), gstate.boneMatrix+i*12); - nsum += norm * weights[i]; - } - } - } - - // Yes, we really must multiply by the world matrix too. - Vec3ByMatrix43(out, psum.AsArray(), gstate.worldMatrix); - if (reader.hasNormal()) { - normal = nsum; - if (gstate.areNormalsReversed()) { - normal = -normal; - } - Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); - worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1); + Vec3ByMatrix43(out, pos, gstate.worldMatrix); + if (reader.hasNormal()) { + if (gstate.areNormalsReversed()) { + normal = -normal; } + Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); + worldnormal = worldnormal.NormalizedOr001(cpu_info.bSSE4_1); } // Perform lighting here if enabled. @@ -398,7 +343,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt source = normal.Normalized(cpu_info.bSSE4_1); } else { reader.Goto(index); - ReadWeightedNormal(source, reader, vertType, skinningEnabled); + if (reader.hasNormal()) + reader.ReadNrm(source.AsArray()); + if (gstate.areNormalsReversed()) + source = -source; source.Normalize(); } if (!reader.hasNormal()) { @@ -413,7 +361,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt } else { // Need to read the normal for this vertex and weight it again.. reader.Goto(index); - ReadWeightedNormal(source, reader, vertType, skinningEnabled); + if (reader.hasNormal()) + reader.ReadNrm(source.AsArray()); + if (gstate.areNormalsReversed()) + source = -source; } if (!reader.hasNormal()) { ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); @@ -639,7 +590,7 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy result->drawIndexed = true; // If we don't support custom cull in the shader, process it here. - if (!gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE) && vertexCount > 0 && !throughmode) { + if (!gstate_c.Use(GPU_USE_CULL_DISTANCE) && vertexCount > 0 && !throughmode) { const u16 *indsIn = (const u16 *)inds; u16 *newInds = inds + vertexCount; u16 *indsOut = newInds; @@ -653,9 +604,9 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy // First, check inside/outside directions for each index. for (int i = 0; i < vertexCount; ++i) { float z = transformed[indsIn[i]].z / transformed[indsIn[i]].pos_w; - if (z >= maxZValue) + if (z > maxZValue) outsideZ[i] = 1; - else if (z <= minZValue) + else if (z < minZValue) outsideZ[i] = -1; else outsideZ[i] = 0; @@ -722,7 +673,7 @@ void SoftwareTransform::CalcCullParams(float &minZValue, float &maxZValue) { std::swap(minZValue, maxZValue); } -void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { +void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { // Rectangles always need 2 vertices, disregard the last one if there's an odd number. vertexCount = vertexCount & ~1; numTrans = 0; @@ -783,7 +734,7 @@ void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&i inds = newInds; } -void SoftwareTransform::ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { +void SoftwareTransform::ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { // Lines always need 2 vertices, disregard the last one if there's an odd number. vertexCount = vertexCount & ~1; numTrans = 0; @@ -906,7 +857,7 @@ void SoftwareTransform::ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, inds = newInds; } -void SoftwareTransform::ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { +void SoftwareTransform::ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { numTrans = 0; TransformedVertex *trans = &transformedExpanded[0]; diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index 37dbca399b..480bd18e51 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -65,16 +65,16 @@ public: SoftwareTransform(SoftwareTransformParams ¶ms) : params_(params) { } - void SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale); + void SetProjMatrix(const float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale); void Decode(int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result); void DetectOffsetTexture(int maxIndex); void BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result); protected: void CalcCullParams(float &minZValue, float &maxZValue); - void ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); - void ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); - void ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); + void ExpandRectangles(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); + void ExpandLines(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); + void ExpandPoints(int vertexCount, int &maxIndex, u16 *&inds, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode); const SoftwareTransformParams ¶ms_; Lin::Matrix4x4 projMatrix_; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index b2358f401b..6fe6436291 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -507,7 +507,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic if (indices) GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound); - VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24)); + VertexDecoder *origVDecoder = GetVertexDecoder(GetVertTypeID(vertType, gstate.getUVGenMode(), decOptions_.applySkinInDecode)); *bytesRead = num_points * origVDecoder->VertexSize(); // Simplify away bones and morph before proceeding @@ -572,7 +572,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic gstate_c.uv.vOff = 0; } - uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), decOptions_.applySkinInDecode); int generatedBytesRead; if (output.count) DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, gstate.getCullMode(), &generatedBytesRead); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index 3b63732c87..f1a834b265 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -63,7 +63,7 @@ struct SurfaceInfo { GEPatchPrimType primType; bool patchFacing; - void Init() { + void BaseInit() { // If specified as 0, uses 1. if (tess_u < 1) tess_u = 1; if (tess_v < 1) tess_v = 1; @@ -88,7 +88,7 @@ struct BezierSurface : public SurfaceInfo { int num_verts_per_patch; void Init(int maxVertices) { - SurfaceInfo::Init(); + SurfaceInfo::BaseInit(); // Downsample until it fits, in case crazy tessellation factors are sent. while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { tess_u--; @@ -126,7 +126,7 @@ struct SplineSurface : public SurfaceInfo { int num_vertices_u; void Init(int maxVertices) { - SurfaceInfo::Init(); + SurfaceInfo::BaseInit(); // Downsample until it fits, in case crazy tessellation factors are sent. while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) { tess_u--; diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 02dea5f739..31c10ecaba 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -58,6 +58,34 @@ static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { return bits >> 24; } +static bool CheckStencilBits(const u8 *src, const VirtualFramebuffer *dstBuffer, int &values, u8 &usedBits) { + switch (dstBuffer->fb_format) { + case GE_FORMAT_565: + // Well, this doesn't make much sense. + return false; + case GE_FORMAT_5551: + usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 2; + break; + case GE_FORMAT_4444: + usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 16; + break; + case GE_FORMAT_8888: + usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 256; + break; + case GE_FORMAT_INVALID: + case GE_FORMAT_DEPTH16: + case GE_FORMAT_CLUT8: + // Inconceivable. + _assert_(false); + return false; + } + + return true; +} + struct StencilUB { float stencilValue; }; @@ -80,11 +108,15 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[1] = { - { "tex" }, + { 0, "tex" }, }; -void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { - ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs, bool useExport) { + std::vector extensions; + if (useExport) + extensions.push_back("#extension GL_ARB_shader_stencil_export : require"); + + ShaderWriter writer(buffer, lang, ShaderStage::Fragment, extensions); writer.HighPrecisionFloat(); writer.DeclareSamplers(samplers); @@ -94,24 +126,28 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n"); - writer.BeginFSMain(uniforms, varyings, FSFLAG_NONE); + writer.BeginFSMain(uniforms, varyings); writer.C(" vec4 index = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a. - writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); - // Bitwise operations on floats, ugh. - writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); + if (useExport) { + writer.C(" gl_FragStencilRefARB = int(roundAndScaleTo255f(index.a));\n"); + } else { + writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); + // Bitwise operations on floats, ugh. + writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); + } if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); } - writer.EndFSMain("outColor", FSFLAG_NONE); + writer.EndFSMain("outColor"); } // This can probably be shared with some other shaders, like reinterpret or the future depth upload. void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { - ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); + ShaderWriter writer(buffer, lang, ShaderStage::Vertex); writer.BeginVSMain(lang.vertexIndex ? Slice::empty() : inputs, Slice::empty(), varyings); @@ -135,10 +171,11 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, return false; } - VirtualFramebuffer *dstBuffer = 0; + VirtualFramebuffer *dstBuffer = nullptr; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { + // TODO: Maybe we should broadcast to all? Most of the time, there's only one. + if (vfb->fb_address == addr && (!dstBuffer || dstBuffer->colorBindSeq < vfb->colorBindSeq)) { dstBuffer = vfb; } } @@ -148,34 +185,15 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, int values = 0; u8 usedBits = 0; + bool useExportShader = draw_->GetDeviceCaps().fragmentShaderStencilWriteSupported; const u8 *src = Memory::GetPointer(addr); if (!src) return false; - switch (dstBuffer->fb_format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. + // Could skip this when doing useExportShader, but then we couldn't optimize usedBits == 0. + if (!CheckStencilBits(src, dstBuffer, values, usedBits)) return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - case GE_FORMAT_DEPTH16: - case GE_FORMAT_CLUT8: - // Inconceivable. - _assert_(false); - break; - } if (usedBits == 0) { if (flags & WriteStencil::STENCIL_IS_ZERO) { @@ -201,7 +219,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, char *fsCode = new char[8192]; char *vsCode = new char[8192]; - GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); + GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs(), useExportShader); GenerateStencilVs(vsCode, shaderLanguageDesc); _assert_msg_(strlen(fsCode) < 8192, "StenFS length error: %d", (int)strlen(fsCode)); @@ -303,24 +321,32 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, draw_->SetScissorRect(0, 0, w, h); draw_->BindPipeline(stencilWritePipeline_); - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } + if (useExportShader) { + // We only need to do one pass if using an export shader. StencilUB ub{}; - if (dstBuffer->fb_format == GE_FORMAT_4444) { - draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); - ub.stencilValue = i * (16.0f / 255.0f); - } else if (dstBuffer->fb_format == GE_FORMAT_5551) { - draw_->SetStencilParams(0xFF, 0xFF, 0xFF); - ub.stencilValue = i * (128.0f / 255.0f); - } else { - draw_->SetStencilParams(0xFF, i, 0xFF); - ub.stencilValue = i * (1.0f / 255.0f); - } + draw_->SetStencilParams(0xFF, 0xFF, 0xFF); draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); draw_->DrawUP(positions, 3); + } else { + for (int i = 1; i < values; i += i) { + if (!(usedBits & i)) { + // It's already zero, let's skip it. + continue; + } + StencilUB ub{}; + if (dstBuffer->fb_format == GE_FORMAT_4444) { + draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); + ub.stencilValue = i * (16.0f / 255.0f); + } else if (dstBuffer->fb_format == GE_FORMAT_5551) { + draw_->SetStencilParams(0xFF, 0xFF, 0xFF); + ub.stencilValue = i * (128.0f / 255.0f); + } else { + draw_->SetStencilParams(0xFF, i, 0xFF); + ub.stencilValue = i * (1.0f / 255.0f); + } + draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); + draw_->DrawUP(positions, 3); + } } if (useBlit) { @@ -331,7 +357,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size, } tex->Release(); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); return true; } diff --git a/GPU/Common/StencilCommon.h b/GPU/Common/StencilCommon.h index e9746012a6..a8c16732e0 100644 --- a/GPU/Common/StencilCommon.h +++ b/GPU/Common/StencilCommon.h @@ -5,5 +5,5 @@ #include "Common/GPU/thin3d.h" // Exposed for automated tests -void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs); +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs, bool useExport); void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 32b234b49a..faeef46975 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -105,19 +105,19 @@ inline int dimHeight(u16 dim) { return 1 << ((dim >> 8) & 0xFF); } -// Vulkan color formats: -// TODO TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw, Draw2D *draw2D) : draw_(draw), draw2D_(draw2D) { decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; - // TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut. - clutBufRaw_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB - clutBufConverted_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB + // It's only possible to have 1KB of palette entries, although we allow 2KB in a hack. + clutBufRaw_ = (u32 *)AllocateAlignedMemory(2048, 16); + clutBufConverted_ = (u32 *)AllocateAlignedMemory(2048, 16); + // Here we need 2KB to expand a 1KB CLUT. + expandClut_ = (u32 *)AllocateAlignedMemory(2048, 16); // Zap so we get consistent behavior if the game fails to load some of the CLUT. - memset(clutBufRaw_, 0, 1024 * sizeof(u32)); - memset(clutBufConverted_, 0, 1024 * sizeof(u32)); + memset(clutBufRaw_, 0, 2048); + memset(clutBufConverted_, 0, 2048); clutBuf_ = clutBufConverted_; // These buffers will grow if necessary, but most won't need more than this. @@ -134,6 +134,7 @@ TextureCacheCommon::~TextureCacheCommon() { FreeAlignedMemory(clutBufConverted_); FreeAlignedMemory(clutBufRaw_); + FreeAlignedMemory(expandClut_); } // Produces a signed 1.23.8 value. @@ -197,7 +198,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.maxLevel = maxLevel * 256; key.minLevel = 0; key.lodBias = (int)(lodBias * 256.0f); - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + if (gstate_c.Use(GPU_USE_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; } break; @@ -281,7 +282,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.mipFilt = 1; key.maxLevel = 9 * 256; key.lodBias = 0.0f; - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + if (gstate_c.Use(GPU_USE_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { key.aniso = true; } break; @@ -371,6 +372,8 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (!Memory::IsValidAddress(texaddr)) { // Bind a null texture and return. Unbind(); + gstate_c.SetTextureIs3D(false); + gstate_c.SetTextureIsArray(false); return nullptr; } @@ -420,11 +423,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; bool isBgraTexture = isBgraBackend_ && !hasClutGPU; - - if (gstate_c.bgraTexture != isBgraTexture) { - gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); - } - gstate_c.bgraTexture = isBgraTexture; + gstate_c.SetTextureIsBGRA(isBgraTexture); if (entryIter != cache_.end()) { entry = entryIter->second.get(); @@ -528,6 +527,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); + gstate_c.SetTextureIsArray(false); if (rehash) { // Update in case any of these changed. entry->sizeInRAM = (textureBitsPerPixel[texFormat] * bufw * h / 2) / 8; @@ -570,9 +570,6 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { nextTexture_ = nullptr; nextNeedsRebuild_ = false; - if (hasClutGPU) { - WARN_LOG_ONCE(clut_fb, G3D, "Render-to-CLUT combined with framebuffer texture at %08x - Not yet supported", texaddr); - } SetTextureFramebuffer(bestCandidate); // sets curTexture3D return nullptr; } @@ -636,6 +633,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); + gstate_c.SetTextureIsArray(false); // Ordinary 2D textures still aren't used by array view in VK. We probably might as well, though, at this point.. failedTexture_ = false; nextTexture_ = entry; @@ -692,6 +690,10 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en relevancy -= 2; } + if (candidate.match.xOffset != 0 && PSP_CoreParameter().compat.flags().DisallowFramebufferAtOffset) { + continue; + } + // Avoid binding as texture the framebuffer we're rendering to. // In Killzone, we split the framebuffer but the matching algorithm can still pick the wrong one, // which this avoids completely. @@ -716,6 +718,7 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en if (i != candidates.size() - 1) cands += "\n"; } + cands += "\n"; WARN_LOG(G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", (int)candidates.size(), @@ -763,7 +766,7 @@ void TextureCacheCommon::Decimate(bool forcePressure) { } // If enabled, we also need to clear the secondary cache. - if (g_Config.bTextureSecondaryCache && (forcePressure || secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE)) { + if (PSP_CoreParameter().compat.flags().SecondaryTextureCache && (forcePressure || secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE)) { const u32 had = secondCacheSizeEstimate_; for (TexCache::iterator iter = secondCache_.begin(); iter != secondCache_.end(); ) { @@ -1019,12 +1022,9 @@ bool TextureCacheCommon::MatchFramebuffer( } // Note the check for texHeight - we really don't care about a stride mismatch if texHeight == 1. + // This also takes care of the 4x1 texture check we used to have here for Burnout Dominator. if (fb_stride_in_bytes != tex_stride_in_bytes && texHeight > 1) { - // Probably irrelevant. Although, as we shall see soon, there are exceptions. - // Burnout Dominator lens flare trick special case. - if (fb_format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT8 && texWidth == 4 && texHeight == 1) { - return true; - } + // Probably irrelevant. return false; } @@ -1036,7 +1036,7 @@ bool TextureCacheCommon::MatchFramebuffer( } return true; } else if (IsClutFormat((GETextureFormat)(entry.format)) || IsDXTFormat((GETextureFormat)(entry.format))) { - WARN_LOG_ONCE(fourEightBit, G3D, "%s fb_format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); + WARN_LOG_ONCE(fourEightBit, G3D, "%s texture format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); return false; } @@ -1088,12 +1088,10 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) gstate_c.curTextureWidth = RoundUpToPowerOf2(gstate_c.curTextureWidth); } - if (gstate_c.bgraTexture) { - gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); - } else if ((gstate_c.curTextureXOffset == 0) != (fbInfo.xOffset == 0) || (gstate_c.curTextureYOffset == 0) != (fbInfo.yOffset == 0)) { + if ((gstate_c.curTextureXOffset == 0) != (fbInfo.xOffset == 0) || (gstate_c.curTextureYOffset == 0) != (fbInfo.yOffset == 0)) { gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); } - gstate_c.bgraTexture = false; + gstate_c.SetTextureIsBGRA(false); gstate_c.curTextureXOffset = fbInfo.xOffset; gstate_c.curTextureYOffset = fbInfo.yOffset; u32 texW = (u32)gstate.getTextureWidth(0); @@ -1103,7 +1101,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) gstate_c.SetNeedShaderTexclamp(true); } - if (channel == RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) { + if (channel == RASTER_DEPTH && !gstate_c.Use(GPU_USE_DEPTH_TEXTURE)) { WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding"); // Flag to bind a null texture if we can't support depth textures. // Should only happen on old OpenGL. @@ -1126,6 +1124,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) } gstate_c.SetTextureIs3D(false); + gstate_c.SetTextureIsArray(true); nextNeedsRehash_ = false; nextNeedsChange_ = false; @@ -1202,7 +1201,7 @@ bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffe void TextureCacheCommon::NotifyConfigChanged() { int scaleFactor = g_Config.iTexScalingLevel; - if (!gstate_c.Supports(GPU_SUPPORTS_TEXTURE_NPOT)) { + if (!gstate_c.Use(GPU_USE_TEXTURE_NPOT)) { // Reduce the scale factor to a power of two (e.g. 2 or 4) if textures must be a power of two. // TODO: In addition we should probably remove these options from the UI in this case. while ((scaleFactor & (scaleFactor - 1)) != 0) { @@ -1231,8 +1230,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { return; } - u32 startPos = gstate.getClutIndexStartPos(); - + _assert_(loadBytes <= 2048); clutTotalBytes_ = loadBytes; clutRenderAddress_ = 0xFFFFFFFF; @@ -1250,6 +1248,10 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { VirtualFramebuffer *chosenFramebuffer = nullptr; for (VirtualFramebuffer *framebuffer : framebuffers) { + // Let's not deal with divide by zero. + if (framebuffer->fb_stride == 0) + continue; + const u32 fb_address = framebuffer->fb_address; const u32 fb_bpp = BufferFormatBytesPerPixel(framebuffer->fb_format); int offset = clutLoadAddr - fb_address; @@ -1273,6 +1275,8 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { if (matchRange && !inMargin && offset < (int)clutRenderOffset_) { WARN_LOG_N_TIMES(clutfb, 5, G3D, "Detected LoadCLUT(%d bytes) from framebuffer %08x (%s), byte offset %d", loadBytes, fb_address, GeBufferFormatToString(framebuffer->fb_format), offset); framebuffer->last_frame_clut = gpuStats.numFlips; + // Also mark used so it's not decimated. + framebuffer->last_frame_used = gpuStats.numFlips; framebuffer->usageFlags |= FB_USAGE_CLUT; bestClutAddress = framebuffer->fb_address; clutRenderOffset_ = (u32)offset; @@ -1295,19 +1299,28 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { desc.height = 1; desc.depth = 1; desc.z_stencil = false; - desc.numColorAttachments = 1; + desc.numLayers = 1; + desc.multiSampleLevel = 0; desc.tag = "dynamic_clut"; dynamicClutFbo_ = draw_->CreateFramebuffer(desc); desc.tag = "dynamic_clut_temp"; dynamicClutTemp_ = draw_->CreateFramebuffer(desc); } + // We'll need to copy from the offset. + const u32 fb_bpp = BufferFormatBytesPerPixel(chosenFramebuffer->fb_format); + const int totalPixelsOffset = clutRenderOffset_ / fb_bpp; + const int clutYOffset = totalPixelsOffset / chosenFramebuffer->fb_stride; + const int clutXOffset = totalPixelsOffset % chosenFramebuffer->fb_stride; + const int scale = chosenFramebuffer->renderScaleFactor; + // Copy the pixels to our temp clut, scaling down if needed and wrapping. - // TODO: Take the clutRenderOffset_ into account here. framebufferManager_->BlitUsingRaster( - chosenFramebuffer->fbo, 0.0f, 0.0f, 512.0f * chosenFramebuffer->renderScaleFactor, 1.0f, + chosenFramebuffer->fbo, clutXOffset * scale, clutYOffset * scale, (clutXOffset + 512.0f) * scale, (clutYOffset + 1.0f) * scale, dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, - false, chosenFramebuffer->renderScaleFactor, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); + false, scale, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); + + framebufferManager_->RebindFramebuffer("after_copy_clut_to_temp"); clutRenderFormat_ = chosenFramebuffer->fb_format; } NotifyMemInfo(MemBlockFlags::ALLOC, clutAddr, loadBytes, "CLUT"); @@ -1315,6 +1328,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { // It's possible for a game to load CLUT outside valid memory without crashing, should result in zeroes. u32 bytes = Memory::ValidSize(clutAddr, loadBytes); + _assert_(bytes <= 2048); bool performDownload = PSP_CoreParameter().compat.flags().AllowDownloadCLUT; if (GPURecord::IsActive()) performDownload = true; @@ -1542,15 +1556,16 @@ static CheckAlphaResult DecodeDXTBlocks(uint8_t *out, int outPitch, uint32_t tex u32 blockIndex = (y / 4) * (bufw / 4); int blockHeight = std::min(h - y, 4); for (int x = 0; x < minw; x += 4) { + int blockWidth = std::min(minw - x, 4); switch (n) { case 1: - DecodeDXT1Block(dst + outPitch32 * y + x, (const DXT1Block *)src + blockIndex, outPitch32, blockHeight, &alphaSum); + DecodeDXT1Block(dst + outPitch32 * y + x, (const DXT1Block *)src + blockIndex, outPitch32, blockWidth, blockHeight, &alphaSum); break; case 3: - DecodeDXT3Block(dst + outPitch32 * y + x, (const DXT3Block *)src + blockIndex, outPitch32, blockHeight); + DecodeDXT3Block(dst + outPitch32 * y + x, (const DXT3Block *)src + blockIndex, outPitch32, blockWidth, blockHeight); break; case 5: - DecodeDXT5Block(dst + outPitch32 * y + x, (const DXT5Block *)src + blockIndex, outPitch32, blockHeight); + DecodeDXT5Block(dst + outPitch32 * y + x, (const DXT5Block *)src + blockIndex, outPitch32, blockWidth, blockHeight); break; } blockIndex++; @@ -1659,7 +1674,9 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G case GE_CMODE_16BIT_ABGR5551: case GE_CMODE_16BIT_ABGR4444: { - if (clutAlphaLinear_ && mipmapShareClut && !expandTo32bit) { + // The w > 1 check is to not need a case that handles a single pixel + // in DeIndexTexture4Optimal. + if (clutAlphaLinear_ && mipmapShareClut && !expandTo32bit && w >= 4) { // We don't bother with fullalpha here (clutAlphaLinear_) // Here, reverseColors means the CLUT is already reversed. if (reverseColors) { @@ -1676,7 +1693,13 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G if (expandTo32bit) { // We simply expand the CLUT to 32-bit, then we deindex as usual. Probably the fastest way. const u16 *clut = GetCurrentRawClut() + clutSharingOffset; - ConvertFormatToRGBA8888(clutformat, expandClut_, clut, 16); + const int clutStart = gstate.getClutIndexStartPos(); + if (gstate.getClutIndexShift() == 0 || gstate.getClutIndexMask() <= 16) { + ConvertFormatToRGBA8888(clutformat, expandClut_ + clutStart, clut + clutStart, 16); + } else { + // To be safe for shifts and wrap around, convert the entire CLUT. + ConvertFormatToRGBA8888(clutformat, expandClut_, clut, 512); + } fullAlphaMask = 0xFF000000; for (int y = 0; y < h; ++y) { DeIndexTexture4((u32 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, expandClut_, &alphaSum); @@ -1875,7 +1898,14 @@ CheckAlphaResult TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int l if (expandTo32Bit && palFormat != GE_CMODE_32BIT_ABGR8888) { const u16 *clut16raw = (const u16 *)clutBufRaw_ + clutSharingOffset; - ConvertFormatToRGBA8888(GEPaletteFormat(palFormat), expandClut_, clut16raw, 256); + // It's possible to access the latter half of the CLUT using the start pos. + const int clutStart = gstate.getClutIndexStartPos(); + if (clutStart > 256) { + // Access wraps around when start + index goes over. + ConvertFormatToRGBA8888(GEPaletteFormat(palFormat), expandClut_, clut16raw, 512); + } else { + ConvertFormatToRGBA8888(GEPaletteFormat(palFormat), expandClut_ + clutStart, clut16raw + clutStart, 256); + } clut32 = expandClut_; palFormat = GE_CMODE_32BIT_ABGR8888; } @@ -2020,11 +2050,13 @@ void TextureCacheCommon::ApplyTexture() { entry->lastFrame = gpuStats.numFlips; gstate_c.SetTextureFullAlpha(false); gstate_c.SetTextureIs3D(false); + gstate_c.SetTextureIsArray(false); } else { entry->lastFrame = gpuStats.numFlips; BindTexture(entry); gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL); gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); + gstate_c.SetTextureIsArray(false); } } @@ -2045,6 +2077,7 @@ static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferForma } break; case GE_FORMAT_CLUT8: + case GE_FORMAT_INVALID: // Shouldn't happen here. return false; } @@ -2094,7 +2127,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Shader depal is not supported during 3D texturing or depth texturing, and requires 32-bit integer instructions in the shader. bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && - !depth && + !depth && clutRenderAddress_ == 0xFFFFFFFF && !gstate_c.curTextureIs3D && draw_->GetShaderLanguageDesc().bitwiseOps; @@ -2113,14 +2146,26 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer u32 depthUpperBits = 0; if (need_depalettize) { - clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); - smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->fb_format, clutTexture.rampLength); + if (clutRenderAddress_ == 0xFFFFFFFF) { + clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); + smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->fb_format, clutTexture.rampLength); + } else { + // The CLUT texture is dynamic, it's the framebuffer pointed to by clutRenderAddress. + // Instead of texturing directly from that, we copy to a temporary CLUT texture. + GEBufferFormat expectedCLUTBufferFormat = (GEBufferFormat)clutFormat; + + // OK, figure out what format we want our framebuffer in, so it can be reinterpreted if needed. + // If no reinterpretation is needed, we'll automatically just get a copy shader. + float scaleFactorX = 1.0f; + Draw2DPipeline *reinterpret = framebufferManager_->GetReinterpretPipeline(clutRenderFormat_, expectedCLUTBufferFormat, &scaleFactorX); + framebufferManager_->BlitUsingRaster(dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, dynamicClutFbo_, 0.0f, 0.0f, scaleFactorX * 512.0f, 1.0f, false, 1.0f, reinterpret, "reinterpret_clut"); + } if (useShaderDepal) { // Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture. BindAsClutTexture(clutTexture.texture, smoothedDepal); - framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, Draw::ALL_LAYERS); // Vulkan needs to do some extra work here to pick out the native handle from Draw. BoundFramebufferTexture(); @@ -2147,7 +2192,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer CheckAlphaResult alphaStatus = CheckCLUTAlpha((const uint8_t *)clutBufRaw_, clutFormat, clutTotalColors); gstate_c.SetTextureFullAlpha(alphaStatus == CHECKALPHA_FULL); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); InvalidateLastTexture(); return; } @@ -2159,9 +2204,6 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer } if (textureShader) { - const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); - ClutTexture clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); - bool needsDepthXSwizzle = depthUpperBits == 2; int depalWidth = framebuffer->renderWidth; @@ -2196,8 +2238,12 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }; draw_->SetViewports(1, &vp); - draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, 0); - draw_->BindTexture(1, clutTexture.texture); + draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); + if (clutRenderAddress_ == 0xFFFFFFFF) { + draw_->BindTexture(1, clutTexture.texture); + } else { + draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT, 0); + } Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false); Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(smoothedDepal); draw_->BindSamplerStates(0, 1, &nearest); @@ -2212,7 +2258,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer draw_->BindTexture(0, nullptr); framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, Draw::ALL_LAYERS); BoundFramebufferTexture(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); @@ -2221,11 +2267,11 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer CheckAlphaResult alphaStatus = CheckCLUTAlpha((const uint8_t *)clutBufRaw_, clutFormat, clutTotalColors); gstate_c.SetTextureFullAlpha(alphaStatus == CHECKALPHA_FULL); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); } else { framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer"); - framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, Draw::ALL_LAYERS); BoundFramebufferTexture(); gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF); @@ -2322,7 +2368,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { // We don't know about alpha at all. gstate_c.SetTextureFullAlpha(false); - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); shaderManager_->DirtyLastShader(); SamplerCacheKey samplerKey = GetFramebufferSamplingParams(texWidth, texHeight); @@ -2401,7 +2447,7 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) { } // Don't give up just yet. Let's try the secondary cache if it's been invalidated before. - if (g_Config.bTextureSecondaryCache) { + if (PSP_CoreParameter().compat.flags().SecondaryTextureCache) { // Don't forget this one was unreliable (in case we match a secondary entry.) entry->status |= TexCacheEntry::STATUS_UNRELIABLE; @@ -2581,7 +2627,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt int lastW = gstate.getTextureWidth(i - 1); int lastH = gstate.getTextureHeight(i - 1); - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (gstate_c.Use(GPU_USE_TEXTURE_LOD_CONTROL)) { if (tw != 1 && tw != (lastW >> 1)) plan.badMipSizes = true; else if (th != 1 && th != (lastH >> 1)) @@ -2600,15 +2646,22 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt plan.scaleFactor = plan.scaleFactor > 4 ? 4 : (plan.scaleFactor > 2 ? 2 : 1); } + bool isFakeMipmapChange = IsFakeMipmapChange(); + if (plan.badMipSizes) { // Check for pure 3D texture. int tw = gstate.getTextureWidth(0); int th = gstate.getTextureHeight(0); bool pure3D = true; - for (int i = 0; i < plan.levelsToLoad; i++) { - if (gstate.getTextureWidth(i) != gstate.getTextureWidth(0) || gstate.getTextureHeight(i) != gstate.getTextureHeight(0)) { - pure3D = false; + if (!isFakeMipmapChange) { + for (int i = 0; i < plan.levelsToLoad; i++) { + if (gstate.getTextureWidth(i) != gstate.getTextureWidth(0) || gstate.getTextureHeight(i) != gstate.getTextureHeight(0)) { + pure3D = false; + break; + } } + } else { + pure3D = false; } if (pure3D && draw_->GetDeviceCaps().texture3DSupported) { @@ -2731,11 +2784,13 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt // Always load base level texture here plan.baseLevelSrc = 0; - if (IsFakeMipmapChange()) { + if (isFakeMipmapChange) { // NOTE: Since the level is not part of the cache key, we assume it never changes. plan.baseLevelSrc = std::max(0, gstate.getTexLevelOffset16() / 16); plan.levelsToCreate = 1; plan.levelsToLoad = 1; + // Make sure we already decided not to do a 3D texture above. + _dbg_assert_(plan.depth == 1); } if (plan.isVideo || plan.depth != 1 || plan.decodeToClut8) { @@ -2782,7 +2837,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, i decPitch = stride; } - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { texDecFlags |= TexDecodeFlags::EXPAND32; } if (entry.status & TexCacheEntry::STATUS_CLUT_GPU) { diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 889dbb85b5..7e20739eee 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -410,7 +410,7 @@ protected: static CheckAlphaResult CheckCLUTAlpha(const uint8_t *pixelData, GEPaletteFormat clutFmt, int w); - inline u32 QuickTexHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, GETextureFormat format, TexCacheEntry *entry) const { + inline u32 QuickTexHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, GETextureFormat format, const TexCacheEntry *entry) const { if (replacer.Enabled()) { return replacer.ComputeHash(addr, bufw, w, h, format, entry->maxSeenV); } @@ -507,7 +507,7 @@ protected: bool isBgraBackend_ = false; - u32 expandClut_[256]; + u32 *expandClut_; }; inline bool TexCacheEntry::Matches(u16 dim2, u8 format2, u8 maxLevel2) const { diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index d7788077a6..a12be66cb9 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -421,9 +421,9 @@ class DXTDecoder { public: inline void DecodeColors(const DXT1Block *src, bool ignore1bitAlpha); inline void DecodeAlphaDXT5(const DXT5Block *src); - inline void WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int height); - inline void WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int height); - inline void WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int height); + inline void WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int width, int height); + inline void WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int width, int height); + inline void WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int width, int height); bool AnyNonFullAlpha() const { return anyNonFullAlpha_; } @@ -507,11 +507,11 @@ void DXTDecoder::DecodeAlphaDXT5(const DXT5Block *src) { } } -void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int height) { +void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int width, int height) { bool anyColor3 = false; for (int y = 0; y < height; y++) { int colordata = src->lines[y]; - for (int x = 0; x < 4; x++) { + for (int x = 0; x < width; x++) { int col = colordata & 3; if (col == 3) { anyColor3 = true; @@ -527,11 +527,11 @@ void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int } } -void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int height) { +void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int width, int height) { for (int y = 0; y < height; y++) { int colordata = src->color.lines[y]; u32 alphadata = src->alphaLines[y]; - for (int x = 0; x < 4; x++) { + for (int x = 0; x < width; x++) { dst[x] = colors_[colordata & 3] | (alphadata << 28); colordata >>= 2; alphadata >>= 4; @@ -540,13 +540,13 @@ void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int } } -void DXTDecoder::WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int height) { +void DXTDecoder::WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int width, int height) { // 48 bits, 3 bit index per pixel, 12 bits per line. u64 alphadata = ((u64)(u16)src->alphadata1 << 32) | (u32)src->alphadata2; for (int y = 0; y < height; y++) { int colordata = src->color.lines[y]; - for (int x = 0; x < 4; x++) { + for (int x = 0; x < width; x++) { dst[x] = colors_[colordata & 3] | (alpha_[alphadata & 7] << 24); colordata >>= 2; alphadata >>= 3; @@ -619,38 +619,34 @@ uint32_t GetDXT5Texel(const DXT5Block *src, int x, int y) { } // This could probably be done faster by decoding two or four blocks at a time with SSE/NEON. -void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, u32 *alpha) { +void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int width, int height, u32 *alpha) { DXTDecoder dxt; dxt.DecodeColors(src, false); - dxt.WriteColorsDXT1(dst, src, pitch, height); + dxt.WriteColorsDXT1(dst, src, pitch, width, height); *alpha &= dxt.AnyNonFullAlpha() ? 0 : 1; } -void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int height) { +void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int width, int height) { DXTDecoder dxt; dxt.DecodeColors(&src->color, true); - dxt.WriteColorsDXT3(dst, src, pitch, height); + dxt.WriteColorsDXT3(dst, src, pitch, width, height); } -void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int height) { +void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int width, int height) { DXTDecoder dxt; dxt.DecodeColors(&src->color, true); dxt.DecodeAlphaDXT5(src); - dxt.WriteColorsDXT5(dst, src, pitch, height); + dxt.WriteColorsDXT5(dst, src, pitch, width, height); } #ifdef _M_SSE inline u32 SSEReduce32And(__m128i value) { - // TODO: Should use a shuffle instead of slri, probably. - value = _mm_and_si128(value, _mm_srli_si128(value, 64)); - value = _mm_and_si128(value, _mm_srli_si128(value, 32)); + value = _mm_and_si128(value, _mm_shuffle_epi32(value, _MM_SHUFFLE(1, 0, 3, 2))); + value = _mm_and_si128(value, _mm_shuffle_epi32(value, _MM_SHUFFLE(1, 1, 1, 1))); return _mm_cvtsi128_si32(value); } inline u32 SSEReduce16And(__m128i value) { - // TODO: Should use a shuffle instead of slri, probably. - value = _mm_and_si128(value, _mm_srli_si128(value, 64)); - value = _mm_and_si128(value, _mm_srli_si128(value, 32)); - u32 mask = _mm_cvtsi128_si32(value); + u32 mask = SSEReduce32And(value); return mask & (mask >> 16); } #endif diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 7a15a32adc..ad54815ff7 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -65,9 +65,9 @@ struct DXT5Block { u8 alpha1; u8 alpha2; }; -void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, u32 *alpha); -void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int height); -void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int height); +void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int width, int height, u32 *alpha); +void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int width, int height); +void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int width, int height); uint32_t GetDXT1Texel(const DXT1Block *src, int x, int y); uint32_t GetDXT3Texel(const DXT3Block *src, int x, int y); @@ -163,22 +163,36 @@ inline void DeIndexTexture4(/*WRITEONLY*/ ClutT *dest, const u8 *indexed, int le ClutT alphaSum = (ClutT)(-1); if (nakedIndex) { - for (int i = 0; i < length; i += 2) { + while (length >= 2) { u8 index = *indexed++; ClutT color0 = clut[index & 0xf]; ClutT color1 = clut[index >> 4]; - dest[i + 0] = color0; - dest[i + 1] = color1; + *dest++ = color0; + *dest++ = color1; alphaSum &= color0 & color1; + length -= 2; + } + if (length) { // Last pixel. Can really only happen in 1xY textures, but making this work generically. + u8 index = *indexed++; + ClutT color0 = clut[index & 0xf]; + *dest = color0; + alphaSum &= color0; } } else { - for (int i = 0; i < length; i += 2) { + while (length >= 2) { u8 index = *indexed++; ClutT color0 = clut[gstate.transformClutIndex((index >> 0) & 0xf)]; ClutT color1 = clut[gstate.transformClutIndex((index >> 4) & 0xf)]; - dest[i + 0] = color0; - dest[i + 1] = color1; + *dest++ = color0; + *dest++ = color1; alphaSum &= color0 & color1; + length -= 2; + } + if (length) { + u8 index = *indexed++; + ClutT color0 = clut[gstate.transformClutIndex((index >> 0) & 0xf)]; + *dest = color0; + alphaSum &= color0; } } @@ -187,10 +201,15 @@ inline void DeIndexTexture4(/*WRITEONLY*/ ClutT *dest, const u8 *indexed, int le template inline void DeIndexTexture4Optimal(ClutT *dest, const u8 *indexed, int length, ClutT color) { - for (int i = 0; i < length; i += 2) { + while (length >= 2) { u8 index = *indexed++; - dest[i + 0] = color | ((index >> 0) & 0xf); - dest[i + 1] = color | ((index >> 4) & 0xf); + *dest++ = color | ((index >> 0) & 0xf); + *dest++ = color | ((index >> 4) & 0xf); + length -= 2; + } + if (length) { + u8 index = *indexed++; + *dest++ = color | ((index >> 0) & 0xf); } } diff --git a/GPU/Common/TextureScalerCommon.cpp b/GPU/Common/TextureScalerCommon.cpp index 3c6e946c2f..a2662a4c04 100644 --- a/GPU/Common/TextureScalerCommon.cpp +++ b/GPU/Common/TextureScalerCommon.cpp @@ -71,7 +71,7 @@ namespace { // 3x3 convolution with Neumann boundary conditions, parallelizable // quite slow, could be sped up a lot // especially handling of separable kernels -void convolve3x3(u32* data, u32* out, const int kernel[3][3], int width, int height, int l, int u) { +void convolve3x3(const u32 *data, u32 *out, const int kernel[3][3], int width, int height, int l, int u) { for (int yb = 0; yb < (u - l) / BLOCK_SIZE + 1; ++yb) { for (int xb = 0; xb < width / BLOCK_SIZE + 1; ++xb) { for (int y = l + yb*BLOCK_SIZE; y < l + (yb + 1)*BLOCK_SIZE && y < u; ++y) { @@ -92,7 +92,7 @@ void convolve3x3(u32* data, u32* out, const int kernel[3][3], int width, int hei } // deposterization: smoothes posterized gradients from low-color-depth (e.g. 444, 565, compressed) sources -void deposterizeH(u32* data, u32* out, int w, int l, int u) { +void deposterizeH(const u32 *data, u32 *out, int w, int l, int u) { static const int T = 8; for (int y = l; y < u; ++y) { for (int x = 0; x < w; ++x) { @@ -120,7 +120,7 @@ void deposterizeH(u32* data, u32* out, int w, int l, int u) { } } } -void deposterizeV(u32* data, u32* out, int w, int h, int l, int u) { +void deposterizeV(const u32 *data, u32 *out, int w, int h, int l, int u) { static const int T = 8; for (int xb = 0; xb < w / BLOCK_SIZE + 1; ++xb) { for (int y = l; y < u; ++y) { @@ -152,7 +152,7 @@ void deposterizeV(u32* data, u32* out, int w, int h, int l, int u) { // generates a distance mask value for each pixel in data // higher values -> larger distance to the surrounding pixels -void generateDistanceMask(u32* data, u32* out, int width, int height, int l, int u) { +void generateDistanceMask(const u32 *data, u32 *out, int width, int height, int l, int u) { for (int yb = 0; yb < (u - l) / BLOCK_SIZE + 1; ++yb) { for (int xb = 0; xb < width / BLOCK_SIZE + 1; ++xb) { for (int y = l + yb*BLOCK_SIZE; y < l + (yb + 1)*BLOCK_SIZE && y < u; ++y) { @@ -183,7 +183,7 @@ void generateDistanceMask(u32* data, u32* out, int width, int height, int l, int } // mix two images based on a mask -void mix(u32* data, u32* source, u32* mask, u32 maskmax, int width, int l, int u) { +void mix(u32 *data, const u32 *source, const u32 *mask, u32 maskmax, int width, int l, int u) { for (int y = l; y < u; ++y) { for (int x = 0; x < width; ++x) { int pos = y*width + x; @@ -211,10 +211,10 @@ static void load_sample(ptrdiff_t w, ptrdiff_t h, ptrdiff_t s, const u8 *pixels, // equivalent to a>=0&&a= (size_t)w||(size_t)y >= (size_t)h) { + if((size_t)x >= (size_t)w || (size_t)y >= (size_t)h) { switch(wrap_mode) { case 0: // Wrap - if(!((w&(w-1))|(h&(h-1)))) { + if(!((w & (w-1)) | (h & (h-1)))) { // Both w and h are powers of 2. x &= w-1; y &= h-1; @@ -239,7 +239,7 @@ static void load_sample(ptrdiff_t w, ptrdiff_t h, ptrdiff_t s, const u8 *pixels, break; } } - memcpy(output, pixels+s*y+4*x, 4); + memcpy(output, pixels + s*y + 4*x, 4); } #define BLOCK 8 @@ -260,7 +260,7 @@ static void init_block( float w00 = B/6.0f , w01 = -C-0.5f*B, w02 = 2.0f*C+0.5f*B , w03 = -C-B/6.0f ; float w10 = 1.0f-B/3.0f,/*w11 = 0.0f ,*/w12 = C+2.0f*B-3.0f , w13 = -C-1.5f*B+2.0f; float w20 = B/6.0f , w21 = C+0.5f*B, w22 = -2.0f*C-2.5f*B+3.0f, w23 = C+1.5f*B-2.0f; - float /*w30 = 0.0f , w31 = 0.0f ,*/w32 = -C , w33 = C+B/6.0f ; + float /*w30 = 0.0f , w31 = 0.0f ,*/w32 = -C , w33 = C+B/6.0f ; // Express the sampling position as a rational // number num/den-1 (off by one, so that num is // always positive, since the C language does @@ -269,9 +269,9 @@ static void init_block( ptrdiff_t den = 2*factor; float inv_den = 1.0f/(float)den; for(int dir = 0; dir < 2; ++dir) { - ptrdiff_t num = (dir?2*y0+1+factor:2*x0+1+factor); - ptrdiff_t *l = (dir?ly:lx), *l0 = (dir?ly0:lx0), *s = (dir?sy:sx); - float (*c)[4] = (dir?cy:cx); + ptrdiff_t num = (dir ? 2*y0+1+factor : 2*x0+1+factor); + ptrdiff_t *l = (dir ? ly : lx), *l0 = (dir ? ly0 : lx0), *s = (dir ? sy : sx); + float (*c)[4] = (dir ? cy : cx); (*l0) = num/den-2; num = num%den; for(ptrdiff_t i = 0, j = 0; i < BLOCK; ++i) { @@ -288,13 +288,13 @@ static void init_block( (*s) = l[BLOCK-1]+4; // Total sampled src pixels in {x|y} direction. } // Get a local copy of the source pixels. - if((*lx0) >=0 && (*ly0) >= 0 && *lx0+(*sx) <= w && *ly0+(*sy) <= h) { + if((*lx0) >=0 && (*ly0) >= 0 && *lx0 + (*sx) <= w && *ly0 + (*sy) <= h) { for(ptrdiff_t iy = 0; iy < (*sy); ++iy) - memcpy(src[iy], src_pixels+src_stride*((*ly0)+iy)+4*(*lx0), (size_t)(4*(*sx))); + memcpy(src[iy], src_pixels+src_stride*((*ly0) + iy) + 4*(*lx0), (size_t)(4*(*sx))); } else { for(ptrdiff_t iy = 0; iy < (*sy); ++iy) for(ptrdiff_t ix = 0; ix < (*sx); ++ix) - load_sample(w, h, src_stride, src_pixels, wrap_mode, (*lx0)+ix, (*ly0)+iy, src[iy]+4*ix); + load_sample(w, h, src_stride, src_pixels, wrap_mode, (*lx0) + ix, (*ly0) + iy, src[iy] + 4*ix); } } @@ -315,14 +315,14 @@ static void upscale_block_c( for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t ix = 0; ix < sx; ++ix) for(ptrdiff_t k = 0; k < 4; ++k) - buf[0][iy][ix][k] = (float)(int)src[iy][4*ix+k]; + buf[0][iy][ix][k] = (float)(int)src[iy][4*ix + k]; // Horizontal pass. for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) { - #define S(i) (buf[0][iy][lx[ix]+i][k]) + #define S(i) (buf[0][iy][lx[ix] + i][k]) float C0 = cx[ix][0], C1 = cx[ix][1], C2 = cx[ix][2], C3 = cx[ix][3]; for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t k = 0; k < 4; ++k) - buf[1][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3; + buf[1][iy][ix][k] = S(0)*C0 + S(1)*C1 + S(2)*C2 + S(3)*C3; #undef S } // Vertical pass. @@ -331,7 +331,7 @@ static void upscale_block_c( float C0 = cy[iy][0], C1 = cy[iy][1], C2 = cy[iy][2], C3 = cy[iy][3]; for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) for(ptrdiff_t k = 0; k < 4; ++k) - buf[0][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3; + buf[0][iy][ix][k] = S(0)*C0 + S(1)*C1 + S(2)*C2 + S(3)*C3; #undef S } // Pack destination pixels. @@ -342,9 +342,9 @@ static void upscale_block_c( float C = buf[0][iy][ix][k]; if(!(C>0.0f)) C = 0.0f; if(C>255.0f) C = 255.0f; - pixel[k] = (u8)(int)(C+0.5f); + pixel[k] = (u8)(int)(C + 0.5f); } - memcpy(dst_pixels+4*(BLOCK*iy+ix), pixel, 4); + memcpy(dst_pixels + 4*(BLOCK*iy + ix), pixel, 4); } } @@ -377,7 +377,7 @@ static void upscale_block_sse2( for(ptrdiff_t iy = 0; iy < sy; ++iy) for(ptrdiff_t ix = 0; ix < sx; ++ix) { int pixel; - memcpy(&pixel, src[iy]+4*ix, 4); + memcpy(&pixel, src[iy] + 4*ix, 4); __m128i C = _mm_cvtsi32_si128(pixel); C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0)); C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0)); @@ -385,7 +385,7 @@ static void upscale_block_sse2( } // Horizontal pass. for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) { - #define S(i) (buf[0][iy][lx[ix]+i]) + #define S(i) (buf[0][iy][lx[ix] + i]) __m128 C0 = _mm_set1_ps(cx[ix][0]), C1 = _mm_set1_ps(cx[ix][1]), C2 = _mm_set1_ps(cx[ix][2]), @@ -395,12 +395,12 @@ static void upscale_block_sse2( _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2), - _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); + _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); #undef S } // Vertical pass. for(ptrdiff_t iy = 0; iy < BLOCK; ++iy) { - #define S(i) (buf[1][ly[iy]+i][ix]) + #define S(i) (buf[1][ly[iy] + i][ix]) __m128 C0 = _mm_set1_ps(cy[iy][0]), C1 = _mm_set1_ps(cy[iy][1]), C2 = _mm_set1_ps(cy[iy][2]), @@ -410,7 +410,7 @@ static void upscale_block_sse2( _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2), - _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); + _mm_mul_ps(_mm_loadu_ps(S(3)), C3))))); #undef S } // Pack destination pixels. @@ -423,14 +423,14 @@ static void upscale_block_sse2( R = _mm_packus_epi16(R, R); R = _mm_packus_epi16(R, R); int pixel = _mm_cvtsi128_si32(R); - memcpy(dst_pixels+4*(BLOCK*iy+ix), &pixel, 4); + memcpy(dst_pixels + 4*(BLOCK*iy+ix), &pixel, 4); } } #endif // defined(_M_SSE) static void upscale_cubic( - ptrdiff_t width, ptrdiff_t height, ptrdiff_t src_stride_in_bytes, const void *src_pixels, - ptrdiff_t dst_stride_in_bytes, void *dst_pixels, + ptrdiff_t width, ptrdiff_t height, ptrdiff_t src_stride_in_bytes, const void *src_pixels, + ptrdiff_t dst_stride_in_bytes, void *dst_pixels, ptrdiff_t scale, float B, float C, int wrap_mode, ptrdiff_t x0, ptrdiff_t y0, ptrdiff_t x1, ptrdiff_t y1) { u8 pixels[BLOCK*BLOCK*4]; @@ -441,16 +441,16 @@ static void upscale_cubic( #else upscale_block_c (width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels); #endif - for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK?y1-y:BLOCK), nx = (x1-x < BLOCK?x1-x:BLOCK); iy < ny; ++iy) - memcpy((u8*)dst_pixels+dst_stride_in_bytes*(y+iy)+4*x, pixels+BLOCK*4*iy, (size_t)(4*nx)); + for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK ? y1-y : BLOCK), nx = (x1-x < BLOCK ? x1-x : BLOCK); iy < ny; ++iy) + memcpy((u8*)dst_pixels + dst_stride_in_bytes*(y+iy) + 4*x, pixels + BLOCK*4*iy, (size_t)(4*nx)); } } // End of pasted cubic upscaler. -void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, int u) { +void scaleBicubicBSpline(int factor, const u32 *data, u32 *out, int w, int h, int l, int u) { const float B = 1.0f, C = 0.0f; - const int wrap_mode = 0; // Clamp + const int wrap_mode = 1; // Clamp upscale_cubic( w, h, w*4, data, factor*w*4, out, @@ -458,9 +458,9 @@ void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, i 0, factor*l, factor*w, factor*u); } -void scaleBicubicMitchell(int factor, u32* data, u32* out, int w, int h, int l, int u) { +void scaleBicubicMitchell(int factor, const u32 *data, u32 *out, int w, int h, int l, int u) { const float B = 0.0f, C = 0.5f; // Actually, Catmull-Rom - const int wrap_mode = 0; // Clamp + const int wrap_mode = 1; // Clamp upscale_cubic( w, h, w*4, data, factor*w*4, out, @@ -478,7 +478,7 @@ const static u8 BILINEAR_FACTORS[4][3][2] = { }; // integral bilinear upscaling by factor f, horizontal part template -void bilinearHt(u32* data, u32* out, int w, int l, int u) { +void bilinearHt(const u32 *data, u32 *out, int w, int l, int u) { static_assert(f > 1 && f <= 5, "Bilinear scaling only implemented for factors 2 to 5"); int outw = w*f; for (int y = l; y < u; ++y) { @@ -497,7 +497,7 @@ void bilinearHt(u32* data, u32* out, int w, int l, int u) { } } } -void bilinearH(int factor, u32* data, u32* out, int w, int l, int u) { +void bilinearH(int factor, const u32 *data, u32 *out, int w, int l, int u) { switch (factor) { case 2: bilinearHt<2>(data, out, w, l, u); break; case 3: bilinearHt<3>(data, out, w, l, u); break; @@ -509,7 +509,7 @@ void bilinearH(int factor, u32* data, u32* out, int w, int l, int u) { // integral bilinear upscaling by factor f, vertical part // gl/gu == global lower and upper bound template -void bilinearVt(u32* data, u32* out, int w, int gl, int gu, int l, int u) { +void bilinearVt(const u32 *data, u32 *out, int w, int gl, int gu, int l, int u) { static_assert(f>1 && f <= 5, "Bilinear scaling only implemented for 2x, 3x, 4x, and 5x"); int outw = w*f; for (int xb = 0; xb < outw / BLOCK_SIZE + 1; ++xb) { @@ -531,7 +531,7 @@ void bilinearVt(u32* data, u32* out, int w, int gl, int gu, int l, int u) { } } } -void bilinearV(int factor, u32* data, u32* out, int w, int gl, int gu, int l, int u) { +void bilinearV(int factor, const u32 *data, u32 *out, int w, int gl, int gu, int l, int u) { switch (factor) { case 2: bilinearVt<2>(data, out, w, gl, gu, l, u); break; case 3: bilinearVt<3>(data, out, w, gl, gu, l, u); break; diff --git a/GPU/Common/TextureShaderCommon.cpp b/GPU/Common/TextureShaderCommon.cpp index 2860389fc2..93428a2238 100644 --- a/GPU/Common/TextureShaderCommon.cpp +++ b/GPU/Common/TextureShaderCommon.cpp @@ -34,8 +34,8 @@ static const VaryingDef varyings[1] = { }; static const SamplerDef samplers[2] = { - { "tex" }, - { "pal" }, + { 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }, + { 1, "pal" }, }; TextureShaderCache::TextureShaderCache(Draw::DrawContext *draw, Draw2D *draw2D) : draw_(draw), draw2D_(draw2D) { } @@ -53,7 +53,7 @@ void TextureShaderCache::DeviceLost() { draw_ = nullptr; } -ClutTexture TextureShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut) { +ClutTexture TextureShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut) { // Simplistic, but works well enough. u32 clutId = clutHash ^ (uint32_t)clutFormat; @@ -233,7 +233,7 @@ std::vector TextureShaderCache::DebugGetShaderIDs(DebugShaderType t } std::string TextureShaderCache::DebugGetShaderString(std::string idstr, DebugShaderType type, DebugShaderStringType stringType) { - uint32_t id; + uint32_t id = 0; sscanf(idstr.c_str(), "%08x", &id); auto iter = depalCache_.find(id); if (iter == depalCache_.end()) diff --git a/GPU/Common/TextureShaderCommon.h b/GPU/Common/TextureShaderCommon.h index a11ee81210..d6a6096f09 100644 --- a/GPU/Common/TextureShaderCommon.h +++ b/GPU/Common/TextureShaderCommon.h @@ -44,7 +44,7 @@ public: ~TextureShaderCache(); Draw2DPipeline *GetDepalettizeShader(uint32_t clutMode, GETextureFormat texFormat, GEBufferFormat pixelFormat, bool smoothedDepal, u32 depthUpperBits); - ClutTexture GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut); + ClutTexture GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut); Draw::SamplerState *GetSampler(bool linearFilter); diff --git a/GPU/Common/VertexDecoderArm.cpp b/GPU/Common/VertexDecoderArm.cpp index 2b93b563f8..e5eea51a3e 100644 --- a/GPU/Common/VertexDecoderArm.cpp +++ b/GPU/Common/VertexDecoderArm.cpp @@ -161,7 +161,7 @@ static const JitLookup jitLookup[] = { JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { dec_ = &dec; - BeginWrite(); + BeginWrite(4096); const u8 *start = AlignCode16(); bool prescaleStep = false; diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index 0ad04dbe5c..4e4385a224 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -143,7 +143,7 @@ static const JitLookup jitLookup[] = { JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { dec_ = &dec; - BeginWrite(); + BeginWrite(4096); const u8 *start = AlignCode16(); bool prescaleStep = false; diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 62eb20ef84..ca38580d65 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -149,7 +149,7 @@ void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBo *indexUpperBound = (u16)upperBound; } -void PrintDecodedVertex(VertexReader &vtx) { +void PrintDecodedVertex(const VertexReader &vtx) { if (vtx.hasNormal()) { float nrm[3]; vtx.ReadNrm(nrm); @@ -1089,7 +1089,7 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, DEBUG_LOG(G3D, "VTYPE: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount); } - skinInDecode = weighttype != 0 && g_Config.bSoftwareSkinning; + skinInDecode = weighttype != 0 && options.applySkinInDecode; if (weighttype) { // && nweights? weightoff = size; diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 6a06093902..a326c0e75e 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -23,6 +23,7 @@ #include "Common/CommonTypes.h" #include "Common/Data/Collections/Hashmaps.h" +#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Log.h" #include "Core/Reporting.h" #include "GPU/ge_constants.h" @@ -165,7 +166,6 @@ public: } break; default: - ERROR_LOG_REPORT_ONCE(fmtnrm, G3D, "Reader: Unsupported Nrm Format %d", decFmt_.nrmfmt); memset(nrm, 0, sizeof(float) * 3); break; } @@ -181,46 +181,38 @@ public: void ReadColor0(float color[4]) const { switch (decFmt_.c0fmt) { case DEC_U8_4: - { - const u8 *b = (const u8 *)(data_ + decFmt_.c0off); - for (int i = 0; i < 4; i++) - color[i] = b[i] * (1.f / 255.f); - } + Uint8x4ToFloat4(color, *(const u32 *)(data_ + decFmt_.c0off)); break; case DEC_FLOAT_4: memcpy(color, data_ + decFmt_.c0off, 16); break; default: - ERROR_LOG_REPORT_ONCE(fmtc0, G3D, "Reader: Unsupported C0 Format %d", decFmt_.c0fmt); memset(color, 0, sizeof(float) * 4); break; } } - void ReadColor0_8888(u8 color[4]) const { + u32 ReadColor0_8888() const { switch (decFmt_.c0fmt) { case DEC_U8_4: { const u8 *b = (const u8 *)(data_ + decFmt_.c0off); - for (int i = 0; i < 4; i++) - color[i] = b[i]; + u32 value; + memcpy(&value, b, 4); + return value; } break; case DEC_FLOAT_4: { const float *f = (const float *)(data_ + decFmt_.c0off); - for (int i = 0; i < 4; i++) - color[i] = f[i] * 255.0f; + return Float4ToUint8x4_NoClamp(f); } break; default: - ERROR_LOG_REPORT_ONCE(fmtc0_8888, G3D, "Reader: Unsupported C0 Format %d", decFmt_.c0fmt); - memset(color, 0, sizeof(u8) * 4); - break; + return 0; } } - void ReadColor1(float color[3]) const { switch (decFmt_.c1fmt) { case DEC_U8_4: @@ -234,7 +226,6 @@ public: memcpy(color, data_ + decFmt_.c1off, 12); break; default: - ERROR_LOG_REPORT_ONCE(fmtc1, G3D, "Reader: Unsupported C1 Format %d", decFmt_.c1fmt); memset(color, 0, sizeof(float) * 3); break; } @@ -289,7 +280,6 @@ public: case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; default: - ERROR_LOG_REPORT_ONCE(fmtw1, G3D, "Reader: Unsupported W1 Format %d", decFmt_.w1fmt); memset(weights + 4, 0, sizeof(float) * 4); break; } @@ -300,8 +290,6 @@ public: bool hasNormal() const { return decFmt_.nrmfmt != 0; } bool hasUV() const { return decFmt_.uvfmt != 0; } bool isThrough() const { return (vtype_ & GE_VTYPE_THROUGH) != 0; } - bool skinningEnabled() const { return vertTypeIsSkinningEnabled(vtype_); } - int numBoneWeights() const { return vertTypeGetNumBoneWeights(vtype_); } void Goto(int index) { data_ = base_ + index * decFmt_.stride; } @@ -313,7 +301,7 @@ private: int vtype_; }; // Debugging utilities -void PrintDecodedVertex(VertexReader &vtx); +void PrintDecodedVertex(const VertexReader &vtx); class VertexDecoder; @@ -335,6 +323,7 @@ typedef void(*JittedVertexDecoder)(const u8 *src, u8 *dst, int count); struct VertexDecoderOptions { bool expandAllWeightsToFloat; bool expand8BitNormalsToFloat; + bool applySkinInDecode; }; class VertexDecoder { @@ -460,7 +449,8 @@ public: bool throughmode; bool skinInDecode; - u8 size; + // With morph and weights, this can be more than 256 bytes. + u16 size; u8 onesize_; u8 weightoff; @@ -593,7 +583,7 @@ private: void Jit_AnyS16Morph(int srcoff, int dstoff); void Jit_AnyFloatMorph(int srcoff, int dstoff); - const VertexDecoder *dec_; + const VertexDecoder *dec_ = nullptr; #if PPSSPP_ARCH(ARM64) Arm64Gen::ARM64FloatEmitter fp; #endif diff --git a/GPU/Common/VertexDecoderX86.cpp b/GPU/Common/VertexDecoderX86.cpp index 3618071c76..728fafc313 100644 --- a/GPU/Common/VertexDecoderX86.cpp +++ b/GPU/Common/VertexDecoderX86.cpp @@ -164,7 +164,7 @@ static const JitLookup jitLookup[] = { JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { dec_ = &dec; - BeginWrite(); + BeginWrite(4096); const u8 *start = this->AlignCode16(); #if PPSSPP_ARCH(X86) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 24f118603f..b7d430fa59 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -23,7 +23,6 @@ #include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/GPU/ShaderWriter.h" #include "Common/GPU/thin3d.h" -#include "Common/VR/PPSSPPVR.h" #include "Core/Config.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -31,6 +30,7 @@ #include "GPU/Common/ShaderUniforms.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/VertexShaderGenerator.h" +#include "GPU/Vulkan/DrawEngineVulkan.h" #undef WRITE @@ -127,33 +127,47 @@ static const char * const boneWeightDecl[9] = { "layout(location = 3) in vec4 w1;\nlayout(location = 4) in vec4 w2;\n", }; -bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { +bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString) { *attrMask = 0; *uniformMask = 0; + *vertexShaderFlags = (VertexShaderFlags)0; bool highpFog = false; bool highpTexcoord = false; - std::vector gl_exts; + std::vector extensions; if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (gl_extensions.EXT_gpu_shader4) { - gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); + extensions.push_back("#extension GL_EXT_gpu_shader4 : enable"); } - bool useClamp = gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); + bool useClamp = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH); if (gl_extensions.EXT_clip_cull_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) { - gl_exts.push_back("#extension GL_EXT_clip_cull_distance : enable"); + extensions.push_back("#extension GL_EXT_clip_cull_distance : enable"); } if (gl_extensions.APPLE_clip_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) { - gl_exts.push_back("#extension GL_APPLE_clip_distance : enable"); + extensions.push_back("#extension GL_APPLE_clip_distance : enable"); } if (gl_extensions.ARB_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) { - gl_exts.push_back("#extension GL_ARB_cull_distance : enable"); + extensions.push_back("#extension GL_ARB_cull_distance : enable"); + } + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { + extensions.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); } } - if (IsVRBuild() && IsMultiviewSupported()) { - gl_exts.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); + + bool useSimpleStereo = id.Bit(VS_BIT_SIMPLE_STEREO); + + if (useSimpleStereo) { + if (compat.shaderLanguage != ShaderLanguage::GLSL_VULKAN) { + *errorString = "Multiview only supported with Vulkan for now"; + return false; + } + extensions.push_back("#extension GL_EXT_multiview : enable"); } - ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts.data(), gl_exts.size()); + + ShaderWriter p(buffer, compat, ShaderStage::Vertex, extensions); + + p.F("// %s\n", VertexShaderDesc(id).c_str()); bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); bool lmode = id.Bit(VS_BIT_LMODE); @@ -230,17 +244,22 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool texCoordInVec3 = false; bool vertexRangeCulling = id.Bit(VS_BIT_VERTEX_RANGE_CULLING) && !isModeThrough; - bool clipClampedDepth = !isModeThrough && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipClampedDepth = !isModeThrough && gstate_c.Use(GPU_USE_DEPTH_CLAMP) && gstate_c.Use(GPU_USE_CLIP_DISTANCE); const char *clipClampedDepthSuffix = "[0]"; const char *vertexRangeClipSuffix = clipClampedDepth ? "[1]" : "[0]"; if (compat.shaderLanguage == GLSL_VULKAN) { WRITE(p, "\n"); - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); + + if (!useHWTransform) { + WRITE(p, "layout (std140, set = 0, binding = 0) uniform frameVars {\n%s};\n", ub_frameStr); + } + + WRITE(p, "layout (std140, set = 1, binding = %d) uniform baseVars {\n%s};\n", DRAW_BINDING_DYNUBO_BASE, ub_baseStr); if (enableLighting || doShadeMapping) - WRITE(p, "layout (std140, set = 0, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform lightVars {\n%s};\n", DRAW_BINDING_DYNUBO_LIGHT, ub_vs_lightsStr); if (enableBones) - WRITE(p, "layout (std140, set = 0, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); + WRITE(p, "layout (std140, set = 1, binding = %d) uniform boneVars {\n%s};\n", DRAW_BINDING_DYNUBO_BONE, ub_vs_bonesStr); if (enableBones) { WRITE(p, "%s", boneWeightDecl[numBoneWeights]); @@ -279,8 +298,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } WRITE(p, "layout (location = 3) out highp float v_fogdepth;\n"); - WRITE(p, "invariant gl_Position;\n"); + WRITE(p, "invariant gl_Position;\n"); } else if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) { // Note: These two share some code after this hellishly large if/else. if (compat.shaderLanguage == HLSL_D3D11) { @@ -416,7 +435,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 gl_Position : POSITION;\n"); } else { WRITE(p, " vec4 gl_Position : SV_Position;\n"); - bool clipRange = vertexRangeCulling && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE); + bool clipRange = vertexRangeCulling && gstate_c.Use(GPU_USE_CLIP_DISTANCE); if (clipClampedDepth && clipRange) { WRITE(p, " float2 gl_ClipDistance : SV_ClipDistance;\n"); clipClampedDepthSuffix = ".x"; @@ -426,7 +445,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag clipClampedDepthSuffix = ""; vertexRangeClipSuffix = ""; } - if (vertexRangeCulling && gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) { + if (vertexRangeCulling && gstate_c.Use(GPU_USE_CULL_DISTANCE)) { WRITE(p, " float2 gl_CullDistance : SV_CullDistance0;\n"); } } @@ -480,8 +499,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform mat4 u_proj_through;\n"); *uniformMask |= DIRTY_PROJTHROUGHMATRIX; } else if (useHWTransform) { - if (IsVRBuild()) { - if (IsMultiviewSupported()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { WRITE(p, "layout(shared) uniform ProjectionMatrix { uniform mat4 u_proj_lens[2]; };\n"); } else { WRITE(p, "uniform mat4 u_proj_lens;\n"); @@ -495,7 +514,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // When transforming by hardware, we need a great deal more uniforms... // TODO: Use 4x3 matrices where possible. Though probably doesn't matter much. WRITE(p, "uniform mat4 u_world;\n"); - if (IsVRBuild() && IsMultiviewSupported()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { WRITE(p, "layout(shared) uniform ViewMatrices { uniform mat4 u_view[2]; };\n"); } else { WRITE(p, "uniform mat4 u_view;\n"); @@ -560,7 +579,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform lowp float u_rotation;\n"); } - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, "uniform lowp float u_scaleX;\n"); WRITE(p, "uniform lowp float u_scaleY;\n"); } @@ -597,7 +616,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } // See comment above this function (GenerateVertexShader). - if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + if (!isModeThrough && gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { // Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection. WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n"); WRITE(p, " float z = v.z / v.w;\n"); @@ -618,7 +637,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 tex;\n"); WRITE(p, " vec4 col;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 6) readonly buffer s_tess_data {\n"); + WRITE(p, "layout (std430, set = 1, binding = %d) readonly buffer s_tess_data {\n", DRAW_BINDING_TESS_STORAGE_BUF); WRITE(p, " TessData tess_data[];\n"); WRITE(p, "};\n"); @@ -626,10 +645,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 basis;\n"); WRITE(p, " vec4 deriv;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 7) readonly buffer s_tess_weights_u {\n"); + WRITE(p, "layout (std430, set = 1, binding = %d) readonly buffer s_tess_weights_u {\n", DRAW_BINDING_TESS_STORAGE_BUF_WU); WRITE(p, " TessWeight tess_weights_u[];\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 8) readonly buffer s_tess_weights_v {\n"); + WRITE(p, "layout (std430, set = 1, binding = %d) readonly buffer s_tess_weights_v {\n", DRAW_BINDING_TESS_STORAGE_BUF_WV); WRITE(p, " TessWeight tess_weights_v[];\n"); WRITE(p, "};\n"); } else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { @@ -833,7 +852,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // The proj_through matrix already has the rotation, if needed. WRITE(p, " vec4 outPos = mul(u_proj_through, vec4(position.xyz, 1.0));\n"); } else { - if (compat.shaderLanguage == GLSL_VULKAN || compat.shaderLanguage == HLSL_D3D11) { + if (compat.shaderLanguage == GLSL_VULKAN) { // Apply rotation from the uniform. WRITE(p, " mat2 displayRotation = mat2(\n"); WRITE(p, " u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), u_rotation == 1.0 ? 1.0 : (u_rotation == 3.0 ? -1.0 : 0.0),\n"); @@ -847,7 +866,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } // The viewport is used in this case, so need to compensate for that. - if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { WRITE(p, " vec4 outPos = depthRoundZVP(pos);\n"); } else { WRITE(p, " vec4 outPos = pos;\n"); @@ -869,7 +888,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (hasNormalTess) { WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%stess.nrm, 0.0), u_world).xyz);\n", flipNormalTess ? "-" : ""); } else { - WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); + WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormalTess ? "-" : ""); } } else { // No skinning, just standard T&L. @@ -877,7 +896,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (hasNormal) WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%snormal, 0.0), u_world).xyz);\n", flipNormal ? "-" : ""); else - WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); + WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormal ? "-" : ""); } } else { static const char *rescale[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; @@ -920,22 +939,22 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } std::string matrixPostfix; - if (IsVRBuild() && IsMultiviewSupported()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { matrixPostfix = "[gl_ViewID_OVR]"; } WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view%s).xyz, 1.0);\n", matrixPostfix.c_str()); // Final view and projection transforms. - if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj_lens%s, viewPos));\n", matrixPostfix.c_str()); WRITE(p, " vec4 orgPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } else { WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } } else { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec4 outPos = mul(u_proj_lens%s, viewPos);\n", matrixPostfix.c_str()); WRITE(p, " vec4 orgPos = mul(u_proj, viewPos);\n"); } else { @@ -1034,11 +1053,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); p.C(" }\n"); p.C(" }\n"); - p.C(" switch (type) {\n"); // Attenuation - p.C(" case 1u:\n"); // GE_LIGHTTYPE_POINT + p.C(" switch (int(type)) {\n"); // Attenuation + p.C(" case 1:\n"); // GE_LIGHTTYPE_POINT p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i); p.C(" break;\n"); - p.C(" case 2u:\n"); // GE_LIGHTTYPE_SPOT + p.C(" case 2:\n"); // GE_LIGHTTYPE_SPOT p.F(" angle = length(u_lightdir%i) == 0.0 ? 0.0 : dot(normalize(u_lightdir%i), toLight);\n", i, i); p.F(" if (angle >= u_lightangle_spotCoef%i.x) {\n", i); p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%i.y <= 0.0 ? 1.0 : pow(angle, u_lightangle_spotCoef%i.y));\n", i, i, i); @@ -1284,7 +1303,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } - if (vertexRangeCulling && !IsVRBuild()) { + if (vertexRangeCulling && !gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n"); @@ -1306,11 +1325,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag const char *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]"; const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]"; - if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { // TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z. - WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", compat.vsOutPrefix, vertexRangeClipSuffix); + // We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.) + WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", compat.vsOutPrefix, vertexRangeClipSuffix, 0.0625 / 65536.0); } - if (gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) { + if (gstate_c.Use(GPU_USE_CULL_DISTANCE)) { // Cull any triangle fully outside in the same direction when depth clamp enabled. WRITE(p, " if (u_cullRangeMin.w > 0.0) {\n"); WRITE(p, " %sgl_CullDistance%s = projPos.z - u_cullRangeMin.z;\n", compat.vsOutPrefix, cull0); @@ -1325,17 +1345,21 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // We've named the output gl_Position in HLSL as well. WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix); - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { // Z correction for the depth buffer if (useHWTransform) { WRITE(p, " %sgl_Position.z = orgPos.z / abs(orgPos.w) * abs(outPos.w);\n", compat.vsOutPrefix); } // HUD scaling - WRITE(p, " if ((u_scaleX < 0.99) || (u_scaleY < 0.99)) {\n"); - WRITE(p, " %sgl_Position.x *= u_scaleX;\n", compat.vsOutPrefix); - WRITE(p, " %sgl_Position.y *= u_scaleY;\n", compat.vsOutPrefix); - WRITE(p, " }\n"); + WRITE(p, " %sgl_Position.x *= u_scaleX;\n", compat.vsOutPrefix); + WRITE(p, " %sgl_Position.y *= u_scaleY;\n", compat.vsOutPrefix); + } + + if (useSimpleStereo && useHWTransform) { + p.C(" float zFactor = 0.2 * float(gl_ViewIndex * 2 - 1);\n"); + p.C(" float zFocus = 0.0;\n"); + p.C(" gl_Position.x += (-gl_Position.z - zFocus) * zFactor;\n"); } if (needsZWHack) { diff --git a/GPU/Common/VertexShaderGenerator.h b/GPU/Common/VertexShaderGenerator.h index c1899001e6..9d3707411c 100644 --- a/GPU/Common/VertexShaderGenerator.h +++ b/GPU/Common/VertexShaderGenerator.h @@ -25,7 +25,13 @@ struct VShaderID; -bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString); +// Can technically be deduced from the vertex shader ID, but this is safer. +enum class VertexShaderFlags : u32 { + MULTI_VIEW = 1, +}; +ENUM_CLASS_BITOPS(VertexShaderFlags); + +bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString); // D3D9 constants. enum { diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index eff16b543b..ce6c3cfec6 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -113,6 +113,8 @@ void DrawEngineD3D11::InitDeviceObjects() { tessDataTransferD3D11 = new TessellationDataTransferD3D11(context_, device_); tessDataTransfer = tessDataTransferD3D11; + + draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1)); } void DrawEngineD3D11::ClearTrackedVertexArrays() { @@ -130,12 +132,14 @@ void DrawEngineD3D11::ClearInputLayoutMap() { inputLayoutMap_.Clear(); } -void DrawEngineD3D11::Resized() { - DrawEngineCommon::Resized(); +void DrawEngineD3D11::NotifyConfigChanged() { + DrawEngineCommon::NotifyConfigChanged(); ClearInputLayoutMap(); } void DrawEngineD3D11::DestroyDeviceObjects() { + draw_->SetInvalidationCallback(InvalidationCallback()); + ClearTrackedVertexArrays(); ClearInputLayoutMap(); delete tessDataTransferD3D11; @@ -322,19 +326,17 @@ VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { ebo->Release(); } +// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. +void DrawEngineD3D11::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + } +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineD3D11::DoFlush() { gpuStats.numFlushes++; - // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. - int curRenderStepId = draw_->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); - lastRenderStepId_ = curRenderStepId; - } - bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); @@ -365,7 +367,7 @@ void DrawEngineD3D11::DoFlush() { // Cannot cache vertex data with morph enabled. bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK); // Also avoid caching when software skinning. - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) useCache = false; if (useCache) { @@ -538,7 +540,7 @@ rotateVBO: D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); @@ -581,6 +583,11 @@ rotateVBO: } } else { PROFILE_THIS_SCOPE("soft"); + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -628,6 +635,10 @@ rotateVBO: swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_NOT_READY && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); } @@ -648,7 +659,7 @@ rotateVBO: if (result.action == SW_DRAW_PRIMITIVES) { D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering()); @@ -701,7 +712,7 @@ rotateVBO: uint8_t clearStencil = clearColor >> 24; draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); - if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; @@ -709,6 +720,7 @@ rotateVBO: framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; @@ -748,6 +760,14 @@ TessellationDataTransferD3D11::~TessellationDataTransferD3D11() { } } +template +static void DoRelease(T *&ptr) { + if (ptr) { + ptr->Release(); + ptr = nullptr; + } +} + void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { struct TessData { float pos[3]; float pad1; @@ -757,19 +777,24 @@ void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const * int size = size_u * size_v; - if (prevSize < size) { + if (prevSize < size || !buf[0]) { prevSize = size; - if (buf[0]) buf[0]->Release(); - if (view[0]) view[0]->Release(); + DoRelease(buf[0]); + DoRelease(view[0]); desc.ByteWidth = size * sizeof(TessData); desc.StructureByteStride = sizeof(TessData); device_->CreateBuffer(&desc, nullptr, &buf[0]); - device_->CreateShaderResourceView(buf[0], nullptr, &view[0]); + if (buf[0]) + device_->CreateShaderResourceView(buf[0], nullptr, &view[0]); + if (!buf[0] || !view[0]) + return; context_->VSSetShaderResources(0, 1, &view[0]); } - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(buf[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + D3D11_MAPPED_SUBRESOURCE map{}; + HRESULT hr = context_->Map(buf[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (FAILED(hr)) + return; uint8_t *data = (uint8_t *)map.pData; float *pos = (float *)(data); @@ -784,34 +809,42 @@ void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const * using Spline::Weight; // Weights U - if (prevSizeWU < weights.size_u) { + if (prevSizeWU < weights.size_u || !buf[1]) { prevSizeWU = weights.size_u; - if (buf[1]) buf[1]->Release(); - if (view[1]) view[1]->Release(); + DoRelease(buf[1]); + DoRelease(view[1]); desc.ByteWidth = weights.size_u * sizeof(Weight); desc.StructureByteStride = sizeof(Weight); device_->CreateBuffer(&desc, nullptr, &buf[1]); - device_->CreateShaderResourceView(buf[1], nullptr, &view[1]); + if (buf[1]) + device_->CreateShaderResourceView(buf[1], nullptr, &view[1]); + if (!buf[1] || !view[1]) + return; context_->VSSetShaderResources(1, 1, &view[1]); } - context_->Map(buf[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight)); + hr = context_->Map(buf[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (SUCCEEDED(hr)) + memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight)); context_->Unmap(buf[1], 0); // Weights V if (prevSizeWV < weights.size_v) { prevSizeWV = weights.size_v; - if (buf[2]) buf[2]->Release(); - if (view[2]) view[2]->Release(); + DoRelease(buf[2]); + DoRelease(view[2]); desc.ByteWidth = weights.size_v * sizeof(Weight); desc.StructureByteStride = sizeof(Weight); device_->CreateBuffer(&desc, nullptr, &buf[2]); - device_->CreateShaderResourceView(buf[2], nullptr, &view[2]); + if (buf[2]) + device_->CreateShaderResourceView(buf[2], nullptr, &view[2]); + if (!buf[2] || !view[2]) + return; context_->VSSetShaderResources(2, 1, &view[2]); } - context_->Map(buf[2], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight)); + hr = context_->Map(buf[2], 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (SUCCEEDED(hr)) + memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight)); context_->Unmap(buf[2], 0); } diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index ca7fb04dbb..2703828516 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -117,7 +117,7 @@ public: class DrawEngineD3D11 : public DrawEngineCommon { public: DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context); - virtual ~DrawEngineD3D11(); + ~DrawEngineD3D11(); void SetShaderManager(ShaderManagerD3D11 *shaderManager) { shaderManager_ = shaderManager; @@ -150,11 +150,13 @@ public: void ClearTrackedVertexArrays() override; - void Resized() override; + void NotifyConfigChanged() override; void ClearInputLayoutMap(); private: + void Invalidate(InvalidationCallbackFlags flags); + void DoFlush(); void ApplyDrawState(int prim); diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index bfbd12f190..124171978f 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -70,7 +70,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerD3D11_->SetTextureCache(textureCacheD3D11_); framebufferManagerD3D11_->SetShaderManager(shaderManagerD3D11_); framebufferManagerD3D11_->SetDrawEngine(&drawEngine_); - framebufferManagerD3D11_->Init(); + framebufferManagerD3D11_->Init(msaaLevel_); textureCacheD3D11_->SetFramebufferManager(framebufferManagerD3D11_); textureCacheD3D11_->SetShaderManager(shaderManagerD3D11_); @@ -82,7 +82,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // No need to flush before the tex scale/offset commands if we are baking // the tex scale/offset into the vertices anyway. UpdateCmdInfo(); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); BuildReportingInfo(); @@ -105,38 +105,20 @@ u32 GPU_D3D11::CheckGPUFeatures() const { // Accurate depth is required because the Direct3D API does not support inverse Z. // So we cannot incorrectly use the viewport transform as the depth range on Direct3D. - // TODO: Breaks text in PaRappa for some reason? - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; - if (draw_->GetDeviceCaps().depthClampSupported) - features |= GPU_SUPPORTS_DEPTH_CLAMP; - - features |= GPU_SUPPORTS_TEXTURE_FLOAT; - features |= GPU_SUPPORTS_INSTANCE_RENDERING; - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_USE_TEXTURE_FLOAT; + features |= GPU_USE_INSTANCE_RENDERING; + features |= GPU_USE_TEXTURE_LOD_CONTROL; uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16); uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16); uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::R5G6B5_UNORM_PACK16); if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) { - features |= GPU_SUPPORTS_16BIT_FORMATS; + features |= GPU_USE_16BIT_FORMATS; } - if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - - // The Phantasy Star hack :( - if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_SUPPORTS_ACCURATE_DEPTH) == 0) { - features |= GPU_USE_DEPTH_RANGE_HACK; - } - - return features; + return CheckGPUFeaturesLate(features); } // Needs to be called on GPU thread, not reporting thread. @@ -149,7 +131,7 @@ void GPU_D3D11::BuildReportingInfo() { } void GPU_D3D11::DeviceLost() { - draw_->InvalidateCachedState(); + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); // Simply drop all caches and textures. // FBOs appear to survive? Or no? shaderManagerD3D11_->ClearShaders(); @@ -170,30 +152,6 @@ void GPU_D3D11::InitClear() { } } -void GPU_D3D11::BeginHostFrame() { - GPUCommon::BeginHostFrame(); - UpdateCmdInfo(); - if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); - framebufferManager_->Resized(); - drawEngine_.Resized(); - textureCache_->NotifyConfigChanged(); - shaderManagerD3D11_->DirtyLastShader(); - resized_ = false; - } -} - -void GPU_D3D11::ReapplyGfxState() { - GPUCommon::ReapplyGfxState(); - - // TODO: Dirty our caches for depth states etc -} - -void GPU_D3D11::EndHostFrame() { - // Probably not really necessary. - draw_->InvalidateCachedState(); -} - void GPU_D3D11::BeginFrame() { GPUCommon::BeginFrame(); @@ -265,15 +223,6 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_D3D11::ClearCacheNextFrame() { - textureCacheD3D11_->ClearNextFrame(); -} - -void GPU_D3D11::ClearShaderCache() { - shaderManagerD3D11_->ClearShaders(); - drawEngine_.ClearInputLayoutMap(); -} - void GPU_D3D11::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index e45c1ab79d..0fece6f431 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -40,33 +40,23 @@ public: void PreExecuteOp(u32 op, u32 diff) override; void ExecuteOp(u32 op, u32 diff) override; - void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; - void BeginHostFrame() override; - void EndHostFrame() override; - protected: void FinishDeferred() override; private: - void Flush() { - drawEngine_.Flush(); - } // void ApplyDrawState(int prim); void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void BeginFrame() override; diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 0560b52941..72668fc718 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -179,13 +179,13 @@ void ShaderManagerD3D11::BindUniforms() { context_->PSSetConstantBuffers(0, 1, ps_cbs); } -void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { +void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) { VShaderID VSID; FShaderID FSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { VSID = lastVSID_; } @@ -212,7 +212,8 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString); + VertexShaderFlags flags; + GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform); vsCache_[VSID] = vs; @@ -227,7 +228,8 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** // Fragment shader not in cache. Let's compile it. std::string genErrorString; uint64_t uniformMask; - GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &genErrorString); + FragmentShaderFlags flags; + GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &genErrorString); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform); fsCache_[FSID] = fs; diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index 0f7a297965..d239daff8f 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -85,7 +85,7 @@ public: ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel); ~ShaderManagerD3D11(); - void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); + void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode); void ClearShaders(); void DirtyLastShader() override; diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 6f113f23d0..2174da2ce9 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -159,7 +159,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState); if (fboTexBindState == FBO_TEX_COPY_BIND_TEX) { - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // No sampler required, we do a plain Load in the pixel shader. fboTexBound_ = true; fboTexBindState = FBO_TEX_NONE; @@ -202,7 +202,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { dynState_.useBlendColor = false; } - if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { + if (gstate_c.Use(GPU_USE_LOGIC_OP)) { // Logic Ops if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) { keys_.blend.blendEnable = false; // Can't have both blend & logic op - although I think the PSP can! @@ -229,7 +229,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - keys_.raster.depthClipEnable = !gstate.isDepthClampEnabled() || !gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + keys_.raster.depthClipEnable = !gstate.isDepthClampEnabled() || !gstate_c.Use(GPU_USE_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. keys_.raster.depthClipEnable = 1; @@ -270,10 +270,11 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } else { keys_.depthStencil.value = 0; // Depth Test - if (gstate.isDepthTestEnabled()) { + if (!IsDepthTestEffectivelyDisabled()) { keys_.depthStencil.depthTestEnable = true; keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { keys_.depthStencil.depthTestEnable = false; keys_.depthStencil.depthWriteEnable = false; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 2dac7b0749..b8e799b476 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -314,7 +314,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { // We don't yet have mip generation, so clamp the number of levels to the ones we can load directly. levels = std::min(plan.levelsToCreate, plan.levelsToLoad); - ID3D11Texture2D *tex; + ID3D11Texture2D *tex = nullptr; D3D11_TEXTURE2D_DESC desc{}; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -329,7 +329,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &tex)); texture = tex; } else { - ID3D11Texture3D *tex; + ID3D11Texture3D *tex = nullptr; D3D11_TEXTURE3D_DESC desc{}; desc.CPUAccessFlags = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -428,7 +428,7 @@ DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format) { } DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS)) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS)) { return DXGI_FORMAT_B8G8R8A8_UNORM; } @@ -470,8 +470,31 @@ bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level D3D11_TEXTURE2D_DESC desc; texture->GetDesc(&desc); - if (desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM) { - // TODO: Support the other formats + int width = desc.Width >> level; + int height = desc.Height >> level; + + switch (desc.Format) { + case DXGI_FORMAT_B8G8R8A8_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_8888); + break; + + case DXGI_FORMAT_B5G6R5_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_565); + break; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_4444); + break; + + case DXGI_FORMAT_B5G5R5A1_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_5551); + break; + + case DXGI_FORMAT_R8_UNORM: + buffer.Allocate(width, height, GPU_DBG_FORMAT_8BIT); + break; + + default: return false; } @@ -481,20 +504,19 @@ bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level ID3D11Texture2D *stagingCopy = nullptr; device_->CreateTexture2D(&desc, nullptr, &stagingCopy); + if (!stagingCopy) + return false; context_->CopyResource(stagingCopy, texture); - int width = desc.Width >> level; - int height = desc.Height >> level; - buffer.Allocate(width, height, GPU_DBG_FORMAT_8888); - D3D11_MAPPED_SUBRESOURCE map; if (FAILED(context_->Map(stagingCopy, level, D3D11_MAP_READ, 0, &map))) { stagingCopy->Release(); return false; } + int bufferRowSize = buffer.PixelSize() * width; for (int y = 0; y < height; y++) { - memcpy(buffer.GetData() + 4 * width * y, (const uint8_t *)map.pData + map.RowPitch * y, 4 * width); + memcpy(buffer.GetData() + bufferRowSize * y, (const uint8_t *)map.pData + map.RowPitch * y, bufferRowSize); } context_->Unmap(stagingCopy, level); diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index fa55ec6b8e..16143b882f 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -134,6 +134,11 @@ bool NotifyCommand(u32 pc) { if (IsBreakpoint(pc, op)) { GPUBreakpoints::ClearTempBreakpoints(); + if (coreState == CORE_POWERDOWN || !gpuDebug) { + breakNext = BreakNext::NONE; + return process; + } + auto info = gpuDebug->DissassembleOp(pc); if (lastStepTime >= 0.0) { NOTICE_LOG(G3D, "Waiting at %08x, %s (%fms)", pc, info.desc.c_str(), (time_now_d() - lastStepTime) * 1000.0); diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index eb3f9fa2bc..593236889a 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -46,6 +46,7 @@ namespace GPURecord { static std::string lastExecFilename; +static uint32_t lastExecVersion; static std::vector lastExecCommands; static std::vector lastExecPushbuf; static std::mutex executeLock; @@ -391,6 +392,11 @@ bool DumpExecute::SubmitCmds(const void *p, u32 sz) { // TODO: Unfortunate. Maybe Texture commands should contain the bufw instead. // The goal here is to realistically combine prims in dumps. Stalling for the bufw flushes. u32_le *ops = (u32_le *)Memory::GetPointerUnchecked(writePos); + + u32 lastTexHigh[8]{}; + for (int i = 0; i < 8; ++i) + lastTexHigh[i] = ((lastTex_[i] & 0xFF000000) >> 8) | ((GE_CMD_TEXBUFWIDTH0 + i) << 24); + for (u32 i = 0; i < sz / 4; ++i) { u32 cmd = ops[i] >> 24; if (cmd >= GE_CMD_TEXBUFWIDTH0 && cmd <= GE_CMD_TEXBUFWIDTH7) { @@ -401,7 +407,7 @@ bool DumpExecute::SubmitCmds(const void *p, u32 sz) { if (bufw == lastBufw_[level]) ops[i] = GE_CMD_NOP << 24; else - ops[i] = (gstate.texbufwidth[level] & 0xFFFF0000) | bufw; + ops[i] = lastTexHigh[level] | bufw; lastBufw_[level] = bufw; } @@ -761,6 +767,7 @@ static void ReplayStop() { lastExecFilename.clear(); lastExecCommands.clear(); lastExecPushbuf.clear(); + lastExecVersion = 0; } bool RunMountedReplay(const std::string &filename) { @@ -769,7 +776,7 @@ bool RunMountedReplay(const std::string &filename) { std::lock_guard guard(executeLock); Core_ListenStopRequest(&ReplayStop); - uint32_t version = 0; + uint32_t version = lastExecVersion; if (lastExecFilename != filename) { PROFILE_THIS_SCOPE("ReplayLoad"); u32 fp = pspFileSystem.OpenFile(filename, FILEACCESS_READ); @@ -812,6 +819,7 @@ bool RunMountedReplay(const std::string &filename) { } lastExecFilename = filename; + lastExecVersion = version; } DumpExecute executor(lastExecPushbuf, lastExecCommands, version); diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 6058546b0f..391b031974 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -60,11 +60,13 @@ static std::vector commands; static std::vector lastRegisters; static std::vector lastTextures; static std::set lastRenderTargets; +static std::vector lastVRAM; enum class DirtyVRAMFlag : uint8_t { CLEAN = 0, - DIRTY = 1, - DRAWN = 2, + UNKNOWN = 1, + DIRTY = 2, + DRAWN = 3, }; static constexpr uint32_t DIRTY_VRAM_SHIFT = 8; static constexpr uint32_t DIRTY_VRAM_ROUND = (1 << DIRTY_VRAM_SHIFT) - 1; @@ -106,8 +108,15 @@ static Path GenRecordingFilename() { } static void DirtyAllVRAM(DirtyVRAMFlag flag) { - for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) - dirtyVRAM[i] = flag; + if (flag == DirtyVRAMFlag::UNKNOWN) { + for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) { + if (dirtyVRAM[i] == DirtyVRAMFlag::CLEAN) + dirtyVRAM[i] = DirtyVRAMFlag::UNKNOWN; + } + } else { + for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) + dirtyVRAM[i] = flag; + } } static void DirtyVRAM(u32 start, u32 sz, DirtyVRAMFlag flag) { @@ -123,10 +132,10 @@ static void DirtyVRAM(u32 start, u32 sz, DirtyVRAMFlag flag) { } static void DirtyDrawnVRAM() { - int w = std::max(gstate.getScissorX2(), gstate.getRegionX2()) + 1; - int h = std::max(gstate.getScissorY2(), gstate.getRegionY2()) + 1; + int w = std::min(gstate.getScissorX2(), gstate.getRegionX2()) + 1; + int h = std::min(gstate.getScissorY2(), gstate.getRegionY2()) + 1; - bool drawZ = gstate.isDepthWriteEnabled() && gstate.isDepthTestEnabled(); + bool drawZ = !gstate.isModeClear() && gstate.isDepthWriteEnabled() && gstate.isDepthTestEnabled(); bool clearZ = gstate.isModeClear() && gstate.isClearModeDepthMask(); if (drawZ || clearZ) { int bytes = 2 * gstate.DepthBufStride() * h; @@ -155,6 +164,7 @@ static void BeginRecording() { pushbuf.resize(pushbuf.size() + sz); gstate.Save((u32_le *)(pushbuf.data() + ptr)); commands.push_back({CommandType::INIT, sz, ptr}); + lastVRAM.resize(2 * 1024 * 1024); // Also save the initial CLUT. GPUDebugBuffer clut; @@ -321,28 +331,73 @@ static Command EmitCommandWithRAM(CommandType t, const void *p, u32 sz, u32 alig return cmd; } +static void UpdateLastVRAM(u32 addr, u32 bytes) { + u32 base = addr & 0x001FFFFF; + if (base + bytes > 0x00200000) { + memcpy(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), 0x00200000 - base); + bytes = base + bytes - 0x00200000; + base = 0; + } + memcpy(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), bytes); +} + +static void ClearLastVRAM(u32 addr, u8 c, u32 bytes) { + u32 base = addr & 0x001FFFFF; + if (base + bytes > 0x00200000) { + memset(&lastVRAM[base], c, 0x00200000 - base); + bytes = base + bytes - 0x00200000; + base = 0; + } + memset(&lastVRAM[base], c, bytes); +} + +static int CompareLastVRAM(u32 addr, u32 bytes) { + u32 base = addr & 0x001FFFFF; + if (base + bytes > 0x00200000) { + int result = memcmp(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), 0x00200000 - base); + if (result != 0) + return result; + + bytes = base + bytes - 0x00200000; + base = 0; + } + return memcmp(&lastVRAM[base], Memory::GetPointerUnchecked(0x04000000 | base), bytes); +} + static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) { addr &= 0x041FFFFF; const bool isTarget = lastRenderTargets.find(addr) != lastRenderTargets.end(); + bool isUnknownVRAM = false; bool isDirtyVRAM = false; bool isDrawnVRAM = false; uint32_t start = (addr >> DIRTY_VRAM_SHIFT) & DIRTY_VRAM_MASK; uint32_t blocks = (sizeInRAM + DIRTY_VRAM_ROUND) >> DIRTY_VRAM_SHIFT; + if (start + blocks >= DIRTY_VRAM_SIZE) + return 0; bool startEven = (addr & DIRTY_VRAM_ROUND) == 0; bool endEven = ((addr + sizeInRAM) & DIRTY_VRAM_ROUND) == 0; for (uint32_t i = 0; i < blocks; ++i) { DirtyVRAMFlag flag = dirtyVRAM[start + i]; + isUnknownVRAM = (isUnknownVRAM || flag == DirtyVRAMFlag::UNKNOWN) && flag != DirtyVRAMFlag::DIRTY && flag != DirtyVRAMFlag::DRAWN; isDirtyVRAM = isDirtyVRAM || flag != DirtyVRAMFlag::CLEAN; isDrawnVRAM = isDrawnVRAM || flag == DirtyVRAMFlag::DRAWN; // Mark the VRAM clean now that it's been copied to VRAM. - if (flag == DirtyVRAMFlag::DIRTY) { + if (flag == DirtyVRAMFlag::UNKNOWN || flag == DirtyVRAMFlag::DIRTY) { if ((i > 0 || startEven) && (i < blocks || endEven)) dirtyVRAM[start + i] = DirtyVRAMFlag::CLEAN; } } + if (isUnknownVRAM && isDirtyVRAM) { + // This means it's only UNKNOWN/CLEAN and not known to be actually dirty. + // Let's check our shadow copy of what we last sent for this VRAM. + int diff = CompareLastVRAM(addr, sizeInRAM); + if (diff == 0) + isDirtyVRAM = false; + } + // The isTarget flag is mostly used for replay of dumps on a PSP. u32 flags = isTarget ? 1 : 0; // The unchangedVRAM flag tells us we can skip recopying. @@ -376,13 +431,16 @@ static void EmitTextureData(int level, u32 texaddr) { u32 pad; }; - u32 flags = GetTargetFlags(texaddr, sizeInRAM); + u32 flags = GetTargetFlags(texaddr, bytes); FramebufData framebuf{ texaddr, bufw, flags }; framebufData.resize(sizeof(framebuf) + bytes); memcpy(&framebufData[0], &framebuf, sizeof(framebuf)); memcpy(&framebufData[sizeof(framebuf)], p, bytes); p = &framebufData[0]; + if ((flags & 2) == 0) + UpdateLastVRAM(texaddr, bytes); + // Okay, now we'll just emit this instead. type = CommandType((int)CommandType::FRAMEBUF0 + level); bytes += (u32)sizeof(framebuf); @@ -418,11 +476,12 @@ static void FlushPrimState(int vcount) { lastRenderTargets.insert(PSP_GetVidMemBase() | gstate.getDepthBufRawAddress()); // We re-flush textures always in case the game changed them... kinda expensive. - // TODO: Dirty textures on transfer/stall/etc. somehow? - // TODO: Or maybe de-dup by validating if it has changed? + bool textureEnabled = gstate.isTextureMapEnabled() || gstate.isAntiAliasEnabled(); + // Play it safe and allow texture coords to emit data too. + bool textureCoords = (gstate.vertType & GE_VTYPE_TC_MASK) != 0; for (int level = 0; level < 8; ++level) { u32 texaddr = gstate.getTextureAddress(level); - if (texaddr) { + if (texaddr && (textureEnabled || textureCoords)) { EmitTextureData(level, texaddr); } } @@ -508,6 +567,9 @@ static void EmitClut(u32 op) { pushbuf.resize(pushbuf.size() + sizeof(data)); memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data)); commands.push_back(cmd); + + if ((flags & 2) == 0) + UpdateLastVRAM(addr, bytes); } EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes, 16); } @@ -558,6 +620,7 @@ static void FinishRecording() { Path filename = WriteRecording(); commands.clear(); pushbuf.clear(); + lastVRAM.clear(); NOTICE_LOG(SYSTEM, "Recording finished"); active = false; @@ -655,8 +718,9 @@ void NotifyMemcpy(u32 dest, u32 src, u32 sz) { sz = Memory::ValidSize(dest, sz); if (sz != 0) { - EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz, 1); - DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY); + EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointerUnchecked(dest), sz, 1); + UpdateLastVRAM(dest, sz); + DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN); } } } @@ -682,20 +746,14 @@ void NotifyMemset(u32 dest, int v, u32 sz) { pushbuf.resize(pushbuf.size() + sizeof(data)); memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data)); commands.push_back(cmd); - DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY); + ClearLastVRAM(dest, v, sz); + DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN); } } void NotifyUpload(u32 dest, u32 sz) { - if (!active) { - return; - } - - if (Memory::IsVRAMAddress(dest)) { - // This also checks the edram translation value. - NotifyMemcpy(dest, dest, sz); - DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY); - } + // This also checks the edram translation value and dirties VRAM. + NotifyMemcpy(dest, dest, sz); } static bool HasDrawCommands() { @@ -790,7 +848,7 @@ void NotifyCPU() { return; } - DirtyAllVRAM(DirtyVRAMFlag::DIRTY); + DirtyAllVRAM(DirtyVRAMFlag::UNKNOWN); } }; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index b8d4bfa0fb..c1123b05d5 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -126,10 +126,11 @@ DrawEngineDX9::~DrawEngineDX9() { } void DrawEngineDX9::InitDeviceObjects() { - + draw_->SetInvalidationCallback(std::bind(&DrawEngineDX9::Invalidate, this, std::placeholders::_1)); } void DrawEngineDX9::DestroyDeviceObjects() { + draw_->SetInvalidationCallback(InvalidationCallback()); ClearTrackedVertexArrays(); } @@ -310,18 +311,17 @@ void DrawEngineDX9::BeginFrame() { lastRenderStepId_ = -1; } +// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. +void DrawEngineDX9::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + } +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineDX9::DoFlush() { gpuStats.numFlushes++; - // In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor. - int curRenderStepId = draw_->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - lastRenderStepId_ = curRenderStepId; - } - bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); @@ -349,7 +349,7 @@ void DrawEngineDX9::DoFlush() { // Cannot cache vertex data with morph enabled. bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK); // Also avoid caching when software skinning. - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) useCache = false; if (useCache) { @@ -522,7 +522,7 @@ rotateVBO: ApplyDrawState(prim); ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_); IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); if (pHardwareVertexDecl) { @@ -546,6 +546,11 @@ rotateVBO: } } } else { + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -597,6 +602,10 @@ rotateVBO: swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_NOT_READY; if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); } @@ -613,7 +622,7 @@ rotateVBO: ApplyDrawStateLate(); - VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, pipelineState_); + VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, true, pipelineState_); if (result.action == SW_DRAW_PRIMITIVES) { if (result.setStencil) { @@ -645,7 +654,7 @@ rotateVBO: device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); - if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; @@ -653,6 +662,7 @@ rotateVBO: framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 9ef5b37c65..e8bb1fbf42 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -105,7 +105,7 @@ public: class DrawEngineDX9 : public DrawEngineCommon { public: DrawEngineDX9(Draw::DrawContext *draw); - virtual ~DrawEngineDX9(); + ~DrawEngineDX9(); void SetShaderManager(ShaderManagerDX9 *shaderManager) { shaderManager_ = shaderManager; @@ -144,6 +144,7 @@ protected: void DecimateTrackedVertexArrays(); private: + void Invalidate(InvalidationCallbackFlags flags); void DoFlush(); void ApplyDrawState(int prim); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 075d89e460..2026b70989 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -69,7 +69,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerDX9_->SetTextureCache(textureCacheDX9_); framebufferManagerDX9_->SetShaderManager(shaderManagerDX9_); framebufferManagerDX9_->SetDrawEngine(&drawEngine_); - framebufferManagerDX9_->Init(); + framebufferManagerDX9_->Init(msaaLevel_); textureCacheDX9_->SetFramebufferManager(framebufferManagerDX9_); textureCacheDX9_->SetShaderManager(shaderManagerDX9_); @@ -81,7 +81,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // No need to flush before the tex scale/offset commands if we are baking // the tex scale/offset into the vertices anyway. UpdateCmdInfo(); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); BuildReportingInfo(); @@ -100,26 +100,14 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) u32 GPU_DX9::CheckGPUFeatures() const { u32 features = GPUCommon::CheckGPUFeatures(); - features |= GPU_SUPPORTS_16BIT_FORMATS; - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_USE_16BIT_FORMATS; + features |= GPU_USE_TEXTURE_LOD_CONTROL; // Accurate depth is required because the Direct3D API does not support inverse Z. // So we cannot incorrectly use the viewport transform as the depth range on Direct3D. - // TODO: Breaks text in PaRappa for some reason? - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; - auto vendor = draw_->GetDeviceCaps().vendor; - - if (!g_Config.bHighQualityDepth) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - // Assume we always have a 24-bit depth buffer. - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - - return features; + return CheckGPUFeaturesLate(features); } GPU_DX9::~GPU_DX9() { @@ -159,19 +147,6 @@ void GPU_DX9::InitClear() { } } -void GPU_DX9::BeginHostFrame() { - GPUCommon::BeginHostFrame(); - UpdateCmdInfo(); - if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); - framebufferManager_->Resized(); - drawEngine_.Resized(); - shaderManagerDX9_->DirtyShader(); - textureCache_->NotifyConfigChanged(); - resized_ = false; - } -} - void GPU_DX9::ReapplyGfxState() { dxstate.Restore(); GPUCommon::ReapplyGfxState(); @@ -245,14 +220,6 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_DX9::ClearCacheNextFrame() { - textureCacheDX9_->ClearNextFrame(); -} - -void GPU_DX9::ClearShaderCache() { - shaderManagerDX9_->ClearCache(true); -} - void GPU_DX9::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 7c6a88d180..621ad79857 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -41,29 +41,21 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; - void BeginHostFrame() override; - protected: void FinishDeferred() override; private: - void Flush() { - drawEngine_.Flush(); - } void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void BeginFrame() override; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 6e20ec45e0..27a42d809b 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -197,7 +197,7 @@ void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) { device_->SetVertexShaderConstantF(creg, f, 1); } -void ShaderManagerDX9::VSSetFloatUniform4(int creg, float data[4]) { +void ShaderManagerDX9::VSSetFloatUniform4(int creg, const float data[4]) { device_->SetVertexShaderConstantF(creg, data, 1); } @@ -544,11 +544,11 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays lastPShader_ = nullptr; } -VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, const ComputedPipelineState &pipelineState) { +VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) { VShaderID VSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { VSID = lastVSID_; } @@ -581,7 +581,8 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString)) { + VertexShaderFlags flags; + if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString)) { vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); } if (!vs || vs->Failed()) { @@ -597,7 +598,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat } delete vs; - ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat, useSkinInDecode); // TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure // that that shader ID is not used when computing the linked shader ID below, because then IDs won't match @@ -606,7 +607,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Can still work with software transform. uint32_t attrMask; uint64_t uniformMask; - bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString); + bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString); _assert_(success); vs = new VSShader(device_, VSID, codeBuffer_, false); } @@ -623,7 +624,8 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Fragment shader not in cache. Let's compile it. std::string errorString; uint64_t uniformMask; - bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &errorString); + FragmentShaderFlags flags; + bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString); // We're supposed to handle all possible cases. _assert_(success); fs = new PSShader(device_, FSID, codeBuffer_); diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 9c7404d856..5dcdddfbce 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -78,7 +78,7 @@ public: ~ShaderManagerDX9(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected - VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, const ComputedPipelineState &pipelineState); + VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState); void DirtyShader(); void DirtyLastShader() override; @@ -104,7 +104,7 @@ private: void VSSetFloat(int creg, float value); void VSSetFloatArray(int creg, const float *value, int count); void VSSetFloat24Uniform3(int creg, const u32 data[3]); - void VSSetFloatUniform4(int creg, float data[4]); + void VSSetFloatUniform4(int creg, const float data[4]); void Clear(); diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index bc1af41143..3a39a9b27e 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -99,9 +99,9 @@ void DrawEngineDX9::ApplyDrawState(int prim) { if (!gstate.isModeClear()) { textureCache_->ApplyTexture(); - if (fboTexBindState_ = FBO_TEX_COPY_BIND_TEX) { + if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // If we are rendering at a higher resolution, linear is probably best for the dest color. device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); @@ -139,7 +139,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS); // If we are rendering at a higher resolution, linear is probably best for the dest color. device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); @@ -228,10 +228,11 @@ void DrawEngineDX9::ApplyDrawState(int prim) { } } else { // Depth Test - if (gstate.isDepthTestEnabled()) { + if (!IsDepthTestEffectivelyDisabled()) { dxstate.depthTest.enable(); dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]); dxstate.depthWrite.set(gstate.isDepthWriteEnabled()); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { dxstate.depthTest.disable(); } diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index dedbb55660..a280c7c590 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -170,7 +170,7 @@ void TextureCacheDX9::StartFrame() { Decimate(); } - if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY)) { + if (gstate_c.Use(GPU_USE_ANISOTROPY)) { DWORD aniso = 1 << g_Config.iAnisotropyLevel; DWORD anisotropyLevel = aniso > maxAnisotropyLevel ? maxAnisotropyLevel : aniso; device_->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropyLevel); diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 5283612f51..7be1adf9d3 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -217,7 +217,7 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int DepthUB ub{}; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { // Don't scale anything, since we're not using factors outside accurate mode. ub.u_depthFactor[0] = 0.0f; ub.u_depthFactor[1] = 1.0f; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 2102e46095..ebdf4051b4 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -117,9 +117,16 @@ void DrawEngineGLES::InitDeviceObjects() { entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color1) }); entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, fog) }); softwareInputLayout_ = render_->CreateInputLayout(entries); + + draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1)); } void DrawEngineGLES::DestroyDeviceObjects() { + if (!draw_) { + return; + } + draw_->SetInvalidationCallback(InvalidationCallback()); + // Beware: this could be called twice in a row, sometimes. for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { if (!frameData_[i].pushVertex && !frameData_[i].pushIndex) @@ -238,22 +245,21 @@ void *DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bind return dest; } +// A new render step means we need to flush any dynamic state. Really, any state that is reset in +// GLQueueRunner::PerformRenderPass. +void DrawEngineGLES::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + } +} + void DrawEngineGLES::DoFlush() { PROFILE_THIS_SCOPE("flush"); FrameData &frameData = frameData_[render_->GetCurFrame()]; gpuStats.numFlushes++; - // A new render step means we need to flush any dynamic state. Really, any state that is reset in - // GLQueueRunner::PerformRenderPass. - int curRenderStepId = render_->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); - lastRenderStepId_ = curRenderStepId; - } - bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); @@ -267,7 +273,7 @@ void DrawEngineGLES::DoFlush() { GEPrimitiveType prim = prevPrim_; VShaderID vsid; - Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, &vsid); + Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode || !CanUseHardwareTransform(prim), &vsid); GLRBuffer *vertexBuffer = nullptr; GLRBuffer *indexBuffer = nullptr; @@ -278,7 +284,7 @@ void DrawEngineGLES::DoFlush() { int vertexCount = 0; bool useElements = true; - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { // If software skinning, we've already predecoded into "decoded". So push that content. size_t size = decodedVerts_ * dec_->GetDecVtxFmt().stride; u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vertexBufferOffset, &vertexBuffer); @@ -331,7 +337,13 @@ void DrawEngineGLES::DoFlush() { } } else { PROFILE_THIS_SCOPE("soft"); + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); + bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255); @@ -389,6 +401,10 @@ void DrawEngineGLES::DoFlush() { swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_NOT_READY; if (result.action == SW_NOT_READY) swTransform.DetectOffsetTexture(maxIndex); @@ -437,7 +453,7 @@ void DrawEngineGLES::DoFlush() { render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask, vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; @@ -446,6 +462,7 @@ void DrawEngineGLES::DoFlush() { } gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied. } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; @@ -470,13 +487,10 @@ void DrawEngineGLES::DoFlush() { GPUDebug::NotifyDraw(); } -bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const { - return decJitCache_->IsInSpace(ptr); -} - +// TODO: Refactor this to a single USE flag. bool DrawEngineGLES::SupportsHWTessellation() const { bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; - return hasTexelFetch && gstate_c.SupportsAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT | GPU_SUPPORTS_INSTANCE_RENDERING); + return hasTexelFetch && gstate_c.UseAll(GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_INSTANCE_RENDERING); } bool DrawEngineGLES::UpdateUseHWTessellation(bool enable) { diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index d843c83ff4..9352291c29 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -61,7 +61,7 @@ public: class DrawEngineGLES : public DrawEngineCommon { public: DrawEngineGLES(Draw::DrawContext *draw); - virtual ~DrawEngineGLES(); + ~DrawEngineGLES(); void SetShaderManager(ShaderManagerGLES *shaderManager) { shaderManager_ = shaderManager; @@ -84,7 +84,6 @@ public: void BeginFrame(); void EndFrame(); - // So that this can be inlined void Flush() { if (!numDrawCalls) @@ -98,8 +97,6 @@ public: DoFlush(); } - bool IsCodePtrVertexDecoder(const u8 *ptr) const; - void DispatchFlush() override { Flush(); } GLPushBuffer *GetPushVertexBuffer() { @@ -117,6 +114,8 @@ protected: bool UpdateUseHWTessellation(bool enable) override; private: + void Invalidate(InvalidationCallbackFlags flags); + void InitDeviceObjects(); void DestroyDeviceObjects(); diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 9d1dc8d3dd..a5a46ca52d 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -70,8 +70,9 @@ void FramebufferManagerGLES::DeviceLost() { } } -void FramebufferManagerGLES::Resized() { - FramebufferManagerCommon::Resized(); +void FramebufferManagerGLES::NotifyDisplayResized() { + FramebufferManagerCommon::NotifyDisplayResized(); + GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); render->Resize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 7bbfa1a510..f67ab65434 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -31,7 +31,7 @@ public: FramebufferManagerGLES(Draw::DrawContext *draw); ~FramebufferManagerGLES(); - void Resized() override; + void NotifyDisplayResized() override; void DeviceLost() override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 65dd71a539..17f0f79552 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -22,6 +22,7 @@ #include "Common/Serialize/Serializer.h" #include "Common/File/FileUtil.h" #include "Common/GraphicsContext.h" +#include "Common/VR/PPSSPPVR.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" @@ -54,7 +55,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) { UpdateVsyncInterval(true); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); shaderManagerGL_ = new ShaderManagerGLES(draw); framebufferManagerGL_ = new FramebufferManagerGLES(draw); @@ -73,7 +74,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerGL_->SetTextureCache(textureCacheGL_); framebufferManagerGL_->SetShaderManager(shaderManagerGL_); framebufferManagerGL_->SetDrawEngine(&drawEngine_); - framebufferManagerGL_->Init(); + framebufferManagerGL_->Init(msaaLevel_); textureCacheGL_->SetFramebufferManager(framebufferManagerGL_); textureCacheGL_->SetShaderManager(shaderManagerGL_); textureCacheGL_->SetDrawEngine(&drawEngine_); @@ -143,6 +144,9 @@ GPU_GLES::~GPU_GLES() { shaderManagerGL_ = nullptr; delete framebufferManagerGL_; delete textureCacheGL_; + + // Clear features so they're not visible in system info. + gstate_c.SetUseFlags(0); } // Take the raw GL extension and versioning data and turn into feature flags. @@ -151,64 +155,52 @@ GPU_GLES::~GPU_GLES() { u32 GPU_GLES::CheckGPUFeatures() const { u32 features = GPUCommon::CheckGPUFeatures(); - features |= GPU_SUPPORTS_16BIT_FORMATS; - - if ((gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA) || (gl_extensions.gpuVendor == GPU_VENDOR_AMD)) - features |= GPU_PREFER_REVERSE_COLOR_ORDER; + features |= GPU_USE_16BIT_FORMATS; if (gl_extensions.GLES3 || !gl_extensions.IsGLES) - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_USE_TEXTURE_LOD_CONTROL; bool canUseInstanceID = gl_extensions.EXT_draw_instanced || gl_extensions.ARB_draw_instanced; bool canDefInstanceID = gl_extensions.IsGLES || gl_extensions.EXT_gpu_shader4 || gl_extensions.VersionGEThan(3, 1); bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID); if (instanceRendering) - features |= GPU_SUPPORTS_INSTANCE_RENDERING; + features |= GPU_USE_INSTANCE_RENDERING; int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits; if (maxVertexTextureImageUnits >= 3) // At least 3 for hardware tessellation - features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; + features |= GPU_USE_VERTEX_TEXTURE_FETCH; if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float) - features |= GPU_SUPPORTS_TEXTURE_FLOAT; - - if (draw_->GetDeviceCaps().depthClampSupported) { - features |= GPU_SUPPORTS_DEPTH_CLAMP | GPU_SUPPORTS_ACCURATE_DEPTH; - // Our implementation of depth texturing needs simple Z range, so can't - // use the extension hacks (yet). - } - - // If we already have a 16-bit depth buffer, we don't need to round. - bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; - if (prefer24) { - if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - if (!gl_extensions.IsGLES || gl_extensions.GLES3) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } else if (prefer24 && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { - // Here we can simulate a 16 bit depth buffer by scaling. - // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else { - // At least do vertex rounding if nothing else. - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; - } - } - - // The Phantasy Star hack :( - if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_SUPPORTS_ACCURATE_DEPTH) == 0) { - features |= GPU_USE_DEPTH_RANGE_HACK; - } + features |= GPU_USE_TEXTURE_FLOAT; if (!draw_->GetShaderLanguageDesc().bitwiseOps) { features |= GPU_USE_FRAGMENT_TEST_CACHE; } + if (IsVREnabled()) { + features |= GPU_USE_VIRTUAL_REALITY; + } + if (IsMultiviewSupported()) { + features |= GPU_USE_SINGLE_PASS_STEREO; + } + + features = CheckGPUFeaturesLate(features); + + if (draw_->GetBugs().Has(Draw::Bugs::ADRENO_RESOURCE_DEADLOCK) && g_Config.bVendorBugChecksEnabled) { + if (PSP_CoreParameter().compat.flags().OldAdrenoPixelDepthRoundingGL) { + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } + } + + // This is a bit ugly, but lets us reuse most of the depth logic in GPUCommon. + if (features & GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) { + if (gl_extensions.IsGLES && !gl_extensions.GLES3) { + // Unsupported, switch to GPU_ROUND_DEPTH_TO_16BIT instead. + features &= ~GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + features |= GPU_ROUND_DEPTH_TO_16BIT; + } + } + return features; } @@ -279,16 +271,6 @@ void GPU_GLES::InitClear() { void GPU_GLES::BeginHostFrame() { GPUCommon::BeginHostFrame(); - UpdateCmdInfo(); - if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); - framebufferManager_->Resized(); - drawEngine_.Resized(); - shaderManagerGL_->DirtyShader(); - textureCache_->NotifyConfigChanged(); - resized_ = false; - } - drawEngine_.BeginFrame(); } @@ -375,19 +357,6 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_GLES::ClearCacheNextFrame() { - textureCacheGL_->ClearNextFrame(); -} - -void GPU_GLES::ClearShaderCache() { - shaderManagerGL_->ClearCache(true); -} - -void GPU_GLES::CleanupBeforeUI() { - // Clear any enabled vertex arrays. - shaderManagerGL_->DirtyLastShader(); -} - void GPU_GLES::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index 98bb1d9362..ce2b363149 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -49,15 +49,11 @@ public: void ReapplyGfxState() override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - void CleanupBeforeUI() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; @@ -69,11 +65,8 @@ protected: void FinishDeferred() override; private: - void Flush() { - drawEngine_.Flush(); - } void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void BeginFrame() override; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 70295fdfdf..15c9422273 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -130,10 +130,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_cullRangeMax, "u_cullRangeMax" }); queries.push_back({ &u_rotation, "u_rotation" }); - if (IsVRBuild()) { - queries.push_back({ &u_scaleX, "u_scaleX" }); - queries.push_back({ &u_scaleY, "u_scaleY" }); - } + // These two are only used for VR, but let's always query them for simplicity. + queries.push_back({ &u_scaleX, "u_scaleX" }); + queries.push_back({ &u_scaleY, "u_scaleY" }); #ifdef USE_BONE_ARRAY queries.push_back({ &u_bone, "u_bone" }); @@ -196,16 +195,16 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, initialize.push_back({ &u_tess_weights_v, 0, TEX_SLOT_SPLINE_WEIGHTS_V }); GLRProgramFlags flags{}; - flags.supportDualSource = (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) != 0; - if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP)) { + flags.supportDualSource = gstate_c.Use(GPU_USE_DUALSOURCE_BLEND); + if (!VSID.Bit(VS_BIT_IS_THROUGH) && gstate_c.Use(GPU_USE_DEPTH_CLAMP)) { flags.useClipDistance0 = true; - if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) + if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_USE_CLIP_DISTANCE)) flags.useClipDistance1 = true; - } else if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) { + } else if (VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Use(GPU_USE_CLIP_DISTANCE)) { flags.useClipDistance0 = true; } - program = render->CreateProgram(shaders, semantics, queries, initialize, flags); + program = render->CreateProgram(shaders, semantics, queries, initialize, nullptr, flags); // The rest, use the "dirty" mechanism. dirtyUniforms = DIRTY_ALL_UNIFORMS; @@ -320,38 +319,35 @@ static inline void FlipProjMatrix(Matrix4x4 &in, bool useBufferedRendering) { in[8] = -in[8]; in[12] = -in[12]; } +} - // In Phantasy Star Portable 2, depth range sometimes goes negative and is clamped by glDepthRange to 0, - // causing graphics clipping glitch (issue #1788). This hack modifies the projection matrix to work around it. - if (gstate_c.Supports(GPU_USE_DEPTH_RANGE_HACK)) { - float zScale = gstate.getViewportZScale() / 65535.0f; - float zCenter = gstate.getViewportZCenter() / 65535.0f; +static inline bool GuessVRDrawingHUD(bool is2D, bool flatScreen) { - // if far depth range < 0 - if (zCenter + zScale < 0.0f) { - // if perspective projection - if (in[11] < 0.0f) { - float depthMax = gstate.getDepthRangeMax() / 65535.0f; - float depthMin = gstate.getDepthRangeMin() / 65535.0f; + bool hud = true; + //HUD cannot be rendered in flatscreen + if (flatScreen) hud = false; + //HUD has to be 2D + else if (!is2D) hud = false; + //HUD has to be blended + else if (!gstate.isAlphaBlendEnabled()) hud = false; + //HUD cannot be rendered with clear color mask + else if (gstate.isClearModeColorMask()) hud = false; + //HUD cannot be rendered with depth color mask + else if (gstate.isClearModeDepthMask()) hud = false; + //HUD texture has to contain alpha channel + else if (!gstate.isTextureAlphaUsed()) hud = false; + //HUD cannot have full texture alpha + else if (gstate_c.textureFullAlpha) hud = false; + //HUD must have full vertex alpha + else if (!gstate_c.vertexFullAlpha && gstate.getDepthTestFunction() == GE_COMP_NEVER) hud = false; + //HUD cannot render FB screenshot + else if (gstate_c.curTextureHeight % 136 <= 1) hud = false; + //HUD cannot be rendered with replace function + else if (gstate.getTextureFunction() == GETexFunc::GE_TEXFUNC_REPLACE) hud = false; + //HUD cannot be rendered with full clear color mask + else if ((gstate.getClearModeColorMask() == 0xFFFFFF) && (gstate.getColorMask() == 0xFFFFFF)) hud = false; - float a = in[10]; - float b = in[14]; - - float n = b / (a - 1.0f); - float f = b / (a + 1.0f); - - f = (n * f) / (n + ((zCenter + zScale) * (n - f) / (depthMax - depthMin))); - - a = (n + f) / (n - f); - b = (2.0f * n * f) / (n - f); - - if (!my_isnan(a) && !my_isnan(b)) { - in[10] = a; - in[14] = b; - } - } - } - } + return hud; } void LinkedShader::use(const ShaderID &VSID) { @@ -363,10 +359,13 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu u64 dirty = dirtyUniforms & availableUniforms; dirtyUniforms = 0; - if (IsVRBuild()) { - dirty |= DIRTY_VIEWMATRIX; - SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor); + // Analyze scene + bool is2D, flatScreen; + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + is2D = Is2DVRObject(gstate.projMatrix, gstate.isModeThrough()); + flatScreen = IsFlatVRScene(); } + if (!dirty) return; @@ -381,23 +380,11 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu render_->SetUniformUI1(&u_depal_mask_shift_off_fmt, val); } - bool is2D, flatScreen; - if (IsVRBuild()) { - // Analyze scene - is2D = Is2DVRObject(gstate.projMatrix, gstate.isModeThrough()); - flatScreen = IsFlatVRScene(); - - // Set HUD mode - bool is3D = gstate.isDepthWriteEnabled(); - bool hud = is2D && !is3D && !flatScreen && - gstate.isModeThrough() && //2D content requires orthographic projection - gstate.isAlphaBlendEnabled() && //2D content has to be blended - !gstate.isLightingEnabled() && //2D content cannot be rendered with lights on - !gstate.isFogEnabled(); //2D content cannot be rendered with fog on - if (hud) { - float scale = 0.5f; - render_->SetUniformF1(&u_scaleX, scale); - render_->SetUniformF1(&u_scaleY, scale / 480.0f * 272.0f); + // Set HUD mode + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + if (GuessVRDrawingHUD(is2D, flatScreen)) { + render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDisplayScale * 480.0f / 272.0f); + render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDisplayScale); } else { render_->SetUniformF1(&u_scaleX, 1.0f); render_->SetUniformF1(&u_scaleY, 1.0f); @@ -406,7 +393,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu // Update any dirty uniforms before we draw if (dirty & DIRTY_PROJMATRIX) { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { Matrix4x4 leftEyeMatrix, rightEyeMatrix; if (flatScreen || is2D) { memcpy(&leftEyeMatrix, gstate.projMatrix, 16 * sizeof(float)); @@ -414,6 +401,9 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } else { UpdateVRProjection(gstate.projMatrix, leftEyeMatrix.m, rightEyeMatrix.m); } + float m4x4[16]; + ConvertMatrix4x3To4x4Transposed(m4x4, gstate.viewMatrix); + UpdateVRParams(gstate.projMatrix, m4x4); FlipProjMatrix(leftEyeMatrix, useBufferedRendering); FlipProjMatrix(rightEyeMatrix, useBufferedRendering); @@ -459,6 +449,9 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } if (dirty & DIRTY_FOGCOLOR) { SetColorUniform3(render_, &u_fogcolor, gstate.fogcolor); + if (IsVREnabled()) { + SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor); + } } if (dirty & DIRTY_FOGCOEF) { float fogcoef[2] = { @@ -537,12 +530,12 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu SetMatrix4x3(render_, &u_world, gstate.worldMatrix); } if (dirty & DIRTY_VIEWMATRIX) { - if (IsVRBuild()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { float leftEyeView[16]; float rightEyeView[16]; ConvertMatrix4x3To4x4Transposed(leftEyeView, gstate.viewMatrix); ConvertMatrix4x3To4x4Transposed(rightEyeView, gstate.viewMatrix); - if (!flatScreen && !is2D) { + if (!is2D) { UpdateVRView(leftEyeView, rightEyeView); } render_->SetUniformM4x4Stereo("u_view", &u_view, leftEyeView, rightEyeView); @@ -564,7 +557,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu float viewZScale = halfActualZRange; float viewZCenter = minz + halfActualZRange; - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) { viewZScale = vpZScale; viewZCenter = vpZCenter; } @@ -728,7 +721,8 @@ void ShaderManagerGLES::DirtyLastShader() { Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) { uint64_t uniformMask; std::string errorString; - if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &errorString)) { + FragmentShaderFlags flags; + if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } @@ -743,7 +737,8 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { uint32_t attrMask; uint64_t uniformMask; std::string errorString; - if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &errorString)) { + VertexShaderFlags flags; + if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } @@ -754,10 +749,10 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { return new Shader(render_, codeBuffer_, desc, params); } -Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID) { +Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID) { if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { *VSID = lastVSID_; } @@ -788,7 +783,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess // Can still work with software transform. VShaderID vsidTemp; - ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat); + ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat, true); vs = CompileVertexShader(vsidTemp); } @@ -936,11 +931,11 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT // as sometimes these features might have an effect on the ID bits. #define CACHE_HEADER_MAGIC 0x83277592 -#define CACHE_VERSION 15 +#define CACHE_VERSION 17 struct CacheHeader { uint32_t magic; uint32_t version; - uint32_t featureFlags; + uint32_t useFlags; uint32_t reserved; int numVertexShaders; int numFragmentShaders; @@ -957,7 +952,7 @@ void ShaderManagerGLES::Load(const Path &filename) { if (!f.ReadArray(&header, 1)) { return; } - if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.featureFlags != gstate_c.featureFlags) { + if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.useFlags != gstate_c.GetUseFlags()) { return; } diskCachePending_.start = time_now_d(); @@ -1113,7 +1108,7 @@ void ShaderManagerGLES::Save(const Path &filename) { header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; header.reserved = 0; - header.featureFlags = gstate_c.featureFlags; + header.useFlags = gstate_c.GetUseFlags(); header.numVertexShaders = GetNumVertexShaders(); header.numFragmentShaders = GetNumFragmentShaders(); header.numLinkedPrograms = GetNumPrograms(); diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index a937318dd1..97ffe6c010 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -161,7 +161,7 @@ public: // This is the old ApplyShader split into two parts, because of annoying information dependencies. // If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards. - Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID); + Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID); LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, u32 vertType, bool useBufferedRendering); void DeviceLost(); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 5485db3c4e..1d06ac01e4 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -158,7 +158,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // fboTexNeedsBind_ won't be set if we can read directly from the target. if (fboTexBindState == FBO_TEX_COPY_BIND_TEX) { // Note that this is positions, not UVs, that we need the copy from. - framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0); // If we are rendering at a higher resolution, linear is probably best for the dest color. renderManager->SetTextureSampler(1, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR, 0.0f); fboTexBound_ = true; @@ -209,7 +209,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // TODO: Get rid of the ifdef #ifndef USING_GLES2 - if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { + if (gstate_c.Use(GPU_USE_LOGIC_OP)) { renderManager->SetLogicOp(logicState.logicOpEnabled, logicOps[(int)logicState.logicOp]); } #endif @@ -232,7 +232,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_USE_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. depthClampEnable = false; @@ -253,7 +253,10 @@ void DrawEngineGLES::ApplyDrawState(int prim) { renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS); } else { // Depth Test - renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]); + bool depthTestUsed = !IsDepthTestEffectivelyDisabled(); + renderManager->SetDepth(depthTestUsed, gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]); + if (depthTestUsed) + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); // Stencil Test if (stencilState.enabled) { @@ -304,7 +307,7 @@ void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) // At this point, we know if the vertices are full alpha or not. // TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? - if (!gstate.isModeClear() && gstate_c.Supports(GPU_USE_FRAGMENT_TEST_CACHE)) { + if (!gstate.isModeClear() && gstate_c.Use(GPU_USE_FRAGMENT_TEST_CACHE)) { // Apply last, once we know the alpha params of the texture. if (gstate.isAlphaTestEnabled() || gstate.isColorTestEnabled()) { fragmentTestCache_->BindTestTexture(TEX_SLOT_ALPHATEST); diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index bbb7c9838b..9584955d34 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -105,7 +105,7 @@ static const GLuint MagFiltGL[2] = { }; void TextureCacheGLES::ApplySamplingParams(const SamplerCacheKey &key) { - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (gstate_c.Use(GPU_USE_TEXTURE_LOD_CONTROL)) { float minLod = (float)key.minLevel / 256.0f; float maxLod = (float)key.maxLevel / 256.0f; float lodBias = (float)key.lodBias / 256.0f; @@ -286,7 +286,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { } } - if (!gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (!gstate_c.Use(GPU_USE_TEXTURE_LOD_CONTROL)) { // If the mip chain is not full.. if (plan.levelsToCreate != plan.maxPossibleLevels) { // We need to avoid creating mips at all, or generate them all - can't be incomplete diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index ed6a553c7e..9ff5b8fd35 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -114,6 +114,9 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { #endif void GPU_Shutdown() { + // Reduce the risk for weird races with the Windows GE debugger. + gpuDebug = nullptr; + // Wait for IsReady, since it might be running on a thread. if (gpu) { gpu->CancelReady(); @@ -123,5 +126,4 @@ void GPU_Shutdown() { } delete gpu; gpu = nullptr; - gpuDebug = nullptr; } diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 808ce53635..860dbc38f3 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -652,6 +652,26 @@ true true + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index e110c20b8b..b8a990374a 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -534,5 +534,11 @@ Shaders + + Shaders + + + Shaders + \ No newline at end of file diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 80f2eefefc..3727f9fcf0 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -428,6 +428,8 @@ GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : ResetMatrices(); PPGeSetDrawContext(draw); + + UpdateMSAALevel(draw); } GPUCommon::~GPUCommon() { @@ -454,7 +456,7 @@ void GPUCommon::UpdateCmdInfo() { // Reconfigure for light ubershader or not. for (int i = 0; i < 4; i++) { - if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) { cmdInfo_[GE_CMD_LIGHTENABLE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE); cmdInfo_[GE_CMD_LIGHTENABLE0 + i].AddDirty(DIRTY_LIGHT_CONTROL); cmdInfo_[GE_CMD_LIGHTTYPE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE); @@ -467,7 +469,7 @@ void GPUCommon::UpdateCmdInfo() { } } - if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) { cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_VERTEXSHADER_STATE); cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_LIGHT_CONTROL); } else { @@ -477,15 +479,25 @@ void GPUCommon::UpdateCmdInfo() { } void GPUCommon::BeginHostFrame() { - UpdateVsyncInterval(resized_); + UpdateVsyncInterval(displayResized_); ReapplyGfxState(); // TODO: Assume config may have changed - maybe move to resize. gstate_c.Dirty(DIRTY_ALL); + + UpdateCmdInfo(); + + UpdateMSAALevel(draw_); + CheckConfigChanged(); + CheckDisplayResized(); + CheckRenderResized(); } void GPUCommon::EndHostFrame() { - + // Probably not necessary. + if (draw_) { + draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); + } } void GPUCommon::Reinitialize() { @@ -607,8 +619,53 @@ bool GPUCommon::BusyDrawing() { return false; } -void GPUCommon::Resized() { - resized_ = true; +void GPUCommon::NotifyConfigChanged() { + configChanged_ = true; +} + +void GPUCommon::NotifyRenderResized() { + renderResized_ = true; +} + +void GPUCommon::NotifyDisplayResized() { + displayResized_ = true; +} + +void GPUCommon::ClearCacheNextFrame() { + textureCache_->ClearNextFrame(); +} + +// Called once per frame. Might also get called during the pause screen +// if "transparent". +void GPUCommon::CheckConfigChanged() { + if (configChanged_) { + ClearCacheNextFrame(); + gstate_c.SetUseFlags(CheckGPUFeatures()); + drawEngineCommon_->NotifyConfigChanged(); + textureCache_->NotifyConfigChanged(); + framebufferManager_->NotifyConfigChanged(); + BuildReportingInfo(); + configChanged_ = false; + } + + // Check needed when running tests. + if (framebufferManager_) { + framebufferManager_->CheckPostShaders(); + } +} + +void GPUCommon::CheckDisplayResized() { + if (displayResized_) { + framebufferManager_->NotifyDisplayResized(); + displayResized_ = false; + } +} + +void GPUCommon::CheckRenderResized() { + if (renderResized_) { + framebufferManager_->NotifyRenderResized(msaaLevel_); + renderResized_ = false; + } } void GPUCommon::DumpNextFrame() { @@ -1188,6 +1245,11 @@ void GPUCommon::BeginFrame() { } GPUDebug::NotifyBeginFrame(); GPURecord::NotifyBeginFrame(); + + if (drawEngineCommon_->EverUsedExactEqualDepth() && !sawExactEqualDepth_) { + sawExactEqualDepth_ = true; + gstate_c.SetUseFlags(CheckGPUFeatures()); + } } void GPUCommon::SlowRunLoop(DisplayList &list) @@ -1834,7 +1896,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { // cull mode int cullMode = gstate.getCullMode(); - uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); drawEngineCommon_->SubmitPrim(verts, inds, prim, count, vertTypeID, cullMode, &bytesRead); // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. @@ -1892,7 +1954,7 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) { goto bail; } else { vertexType = data; - vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode()); + vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); } break; } @@ -2153,29 +2215,50 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { // Just resetting, nothing to check bounds for. - const u32 count = op & 0xFFFFFF; + const u32 count = op & 0xFFFF; if (count == 0) { currentList->bboxResult = false; return; } - if (((count & 7) == 0) && count <= 64) { // Sanity check - const void *control_points = Memory::GetPointer(gstate_c.vertexAddr); + + // Approximate based on timings of several counts on a PSP. + cyclesExecuted += count * 22; + + const bool useInds = (gstate.vertType & GE_VTYPE_IDX_MASK) != 0; + VertexDecoder *dec = drawEngineCommon_->GetVertexDecoder(gstate.vertType); + int bytesRead = (useInds ? 1 : dec->VertexSize()) * count; + + if (Memory::IsValidRange(gstate_c.vertexAddr, bytesRead)) { + const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); if (!control_points) { ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Invalid verts in bounding box check"); currentList->bboxResult = true; return; } - if (gstate.vertType & GE_VTYPE_IDX_MASK) { - ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Indexed bounding box data not supported."); - // Data seems invalid. Let's assume the box test passed. - currentList->bboxResult = true; - return; + const void *inds = nullptr; + if (useInds) { + int indexShift = ((gstate.vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1; + inds = Memory::GetPointerUnchecked(gstate_c.indexAddr); + if (!inds || !Memory::IsValidRange(gstate_c.indexAddr, count << indexShift)) { + ERROR_LOG_REPORT_ONCE(boundingboxInds, G3D, "Invalid inds in bounding box check"); + currentList->bboxResult = true; + return; + } } // Test if the bounding box is within the drawing region. - int bytesRead; - currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType, &bytesRead); + // The PSP only seems to vary the result based on a single range of 0x100. + if (count > 0x200) { + // The second to last set of 0x100 is checked (even for odd counts.) + size_t skipSize = (count - 0x200) * dec->VertexSize(); + currentList->bboxResult = drawEngineCommon_->TestBoundingBox((const uint8_t *)control_points + skipSize, inds, 0x100, gstate.vertType); + } else if (count > 0x100) { + int checkSize = count - 0x100; + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, inds, checkSize, gstate.vertType); + } else { + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, inds, count, gstate.vertType); + } AdvanceVerts(gstate.vertType, count, bytesRead); } else { ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Bad bounding box data: %06x", count); @@ -2983,72 +3066,189 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); - if (!Memory::IsValidAddress(srcBasePtr)) { - ERROR_LOG_REPORT(G3D, "BlockTransfer: Bad source transfer address %08x!", srcBasePtr); - return; - } + // For VRAM, we wrap around when outside valid memory (mirrors still work.) + if ((srcBasePtr & 0x04800000) == 0x04800000) + srcBasePtr &= ~0x00800000; + if ((dstBasePtr & 0x04800000) == 0x04800000) + dstBasePtr &= ~0x00800000; - if (!Memory::IsValidAddress(dstBasePtr)) { - ERROR_LOG_REPORT(G3D, "BlockTransfer: Bad destination transfer address %08x!", dstBasePtr); - return; - } + // Use height less one to account for width, which can be greater or less than stride. + const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; + const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp; + const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; + const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp; - // Check that the last address of both source and dest are valid addresses + bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; + bool srcValid = Memory::IsValidRange(src, srcSize); + bool dstValid = Memory::IsValidRange(dst, dstSize); + bool srcWraps = Memory::IsVRAMAddress(srcBasePtr) && !srcValid; + bool dstWraps = Memory::IsVRAMAddress(dstBasePtr) && !dstValid; - u32 srcLastAddr = srcBasePtr + ((srcY + height - 1) * srcStride + (srcX + width - 1)) * bpp; - u32 dstLastAddr = dstBasePtr + ((dstY + height - 1) * dstStride + (dstX + width - 1)) * bpp; - - if (!Memory::IsValidAddress(srcLastAddr)) { - ERROR_LOG_REPORT(G3D, "Bottom-right corner of source of block transfer is at an invalid address: %08x", srcLastAddr); - return; - } - if (!Memory::IsValidAddress(dstLastAddr)) { - ERROR_LOG_REPORT(G3D, "Bottom-right corner of destination of block transfer is at an invalid address: %08x", srcLastAddr); - return; - } + char tag[128]; + size_t tagSize; // Tell the framebuffer manager to take action if possible. If it does the entire thing, let's just return. - if (!framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) { + if (!framebufferManager_ || !framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) { // Do the copy! (Hm, if we detect a drawn video frame (see below) then we could maybe skip this?) // Can use GetPointerUnchecked because we checked the addresses above. We could also avoid them // entirely by walking a couple of pointers... - if (srcStride == dstStride && (u32)width == srcStride) { - // Common case in God of War, let's do it all in one chunk. + + // Simple case: just a straight copy, no overlap or wrapping. + if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap && srcValid && dstValid) { u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr); - u8 *dst = Memory::GetPointerWriteUnchecked(dstLineStartAddr); - memcpy(dst, src, width * height * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * height * bpp); - } else { + u32 bytesToCopy = width * height * bpp; + + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + memcpy(dstp, srcp, bytesToCopy); + + if (MemBlockInfoDetailed(bytesToCopy)) { + tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, bytesToCopy); + NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag, tagSize); + } + } else if ((srcDstOverlap || srcWraps || dstWraps) && (srcValid || srcWraps) && (dstValid || dstWraps)) { + // This path means we have either src/dst overlap, OR one or both of src and dst wrap. + // This should be uncommon so it's the slowest path. + u32 bytesToCopy = width * bpp; + bool notifyDetail = MemBlockInfoDetailed(srcWraps || dstWraps ? 64 : bytesToCopy); + bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); + if (notifyDetail || notifyAll) { + tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); + } + + auto notifyingMemmove = [&](u32 d, u32 s, u32 sz) { + const u8 *srcp = Memory::GetPointer(s); + u8 *dstp = Memory::GetPointerWrite(d); + memmove(dstp, srcp, sz); + + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, s, sz, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag, tagSize); + } + }; + + for (int y = 0; y < height; y++) { + u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; + u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; + // If we already passed a wrap, we can use the quicker path. + if ((srcLineStartAddr & 0x04800000) == 0x04800000) + srcLineStartAddr &= ~0x00800000; + if ((dstLineStartAddr & 0x04800000) == 0x04800000) + dstLineStartAddr &= ~0x00800000; + // These flags mean there's a wrap inside this line. + bool srcLineWrap = !Memory::IsValidRange(srcLineStartAddr, bytesToCopy); + bool dstLineWrap = !Memory::IsValidRange(dstLineStartAddr, bytesToCopy); + + if (!srcLineWrap && !dstLineWrap) { + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; + memmove(dstp + i, srcp + i, chunk); + } + + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag, tagSize); + } + } else { + // We can wrap at any point, so along with overlap this gets a bit complicated. + // We're just going to do this the slow and easy way. + u32 srcLinePos = srcLineStartAddr; + u32 dstLinePos = dstLineStartAddr; + for (u32 i = 0; i < bytesToCopy; i += 64) { + u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64; + u32 srcValid = Memory::ValidSize(srcLinePos, chunk); + u32 dstValid = Memory::ValidSize(dstLinePos, chunk); + + // First chunk, for which both are valid. + u32 bothSize = std::min(srcValid, dstValid); + if (bothSize != 0) + notifyingMemmove(dstLinePos, srcLinePos, bothSize); + + // Now, whichever side has more valid (or the rest, if only one side must wrap.) + u32 exclusiveSize = std::max(srcValid, dstValid) - bothSize; + if (exclusiveSize != 0 && srcValid >= dstValid) { + notifyingMemmove(PSP_GetVidMemBase(), srcLineStartAddr + bothSize, exclusiveSize); + } else if (exclusiveSize != 0 && srcValid < dstValid) { + notifyingMemmove(dstLineStartAddr + bothSize, PSP_GetVidMemBase(), exclusiveSize); + } + + // Finally, if both src and dst wrapped, that portion. + u32 wrappedSize = chunk - bothSize - exclusiveSize; + if (wrappedSize != 0 && srcValid >= dstValid) { + notifyingMemmove(PSP_GetVidMemBase() + exclusiveSize, PSP_GetVidMemBase(), wrappedSize); + } else if (wrappedSize != 0 && srcValid < dstValid) { + notifyingMemmove(PSP_GetVidMemBase(), PSP_GetVidMemBase() + exclusiveSize, wrappedSize); + } + + srcLinePos += chunk; + dstLinePos += chunk; + if ((srcLinePos & 0x04800000) == 0x04800000) + srcLinePos &= ~0x00800000; + if ((dstLinePos & 0x04800000) == 0x04800000) + dstLinePos &= ~0x00800000; + } + } + } + + if (notifyAll) { + if (srcWraps) { + u32 validSize = Memory::ValidSize(src, srcSize); + NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag, tagSize); + } else { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); + } + if (dstWraps) { + u32 validSize = Memory::ValidSize(dst, dstSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag, tagSize); + } else { + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); + } + } + } else if (srcValid && dstValid) { + u32 bytesToCopy = width * bpp; + bool notifyDetail = MemBlockInfoDetailed(bytesToCopy); + bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize); + if (notifyDetail || notifyAll) { + tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); + } + for (int y = 0; y < height; y++) { u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr); - u8 *dst = Memory::GetPointerWriteUnchecked(dstLineStartAddr); - memcpy(dst, src, width * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp); + const u8 *srcp = Memory::GetPointer(srcLineStartAddr); + u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); + memcpy(dstp, srcp, bytesToCopy); + + // If we're tracking detail, it's useful to have the gaps illustrated properly. + if (notifyDetail) { + NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag, tagSize); + } } + + if (notifyAll) { + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); + } + } else { + // This seems to cause the GE to require a break/reset on a PSP. + // TODO: Handle that and figure out which bytes are still copied? + ERROR_LOG_REPORT_ONCE(invalidtransfer, G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); } - // Fixes Gran Turismo's funky text issue, since it overwrites the current texture. - textureCache_->Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT); - framebufferManager_->NotifyBlockTransferAfter(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason); - } - - const uint32_t numBytes = width * height * bpp; - const uint32_t srcSize = height * srcStride * bpp; - const uint32_t dstSize = height * dstStride * bpp; - // We do the check here on the number of bytes to avoid marking really tiny images. - // Helps perf in GT menu which does insane amounts of these, one for each text character per frame. - if (MemBlockInfoDetailed(numBytes, numBytes)) { - const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - char tag[128]; - size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); + if (framebufferManager_) { + // Fixes Gran Turismo's funky text issue, since it overwrites the current texture. + textureCache_->Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT); + framebufferManager_->NotifyBlockTransferAfter(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason); + } } // TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate. @@ -3059,12 +3259,13 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags // Track stray copies of a framebuffer in RAM. MotoGP does this. if (framebufferManager_->MayIntersectFramebuffer(src) || framebufferManager_->MayIntersectFramebuffer(dest)) { if (!framebufferManager_->NotifyFramebufferCopy(src, dest, size, flags, gstate_c.skipDrawReason)) { - // We use a little hack for PerformReadbackToMemory/PerformWriteColorFromMemory using a VRAM mirror. + // We use matching values in PerformReadbackToMemory/PerformWriteColorFromMemory. // Since they're identical we don't need to copy. - if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) { + if (dest != src) { if (MemBlockInfoDetailed(size)) { - const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); - Memory::Memcpy(dest, src, size, tag.c_str(), tag.size()); + char tag[128]; + size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUMemcpy/", src, size); + Memory::Memcpy(dest, src, size, tag, tagSize); } else { Memory::Memcpy(dest, src, size, "GPUMemcpy"); } @@ -3075,9 +3276,10 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags } if (MemBlockInfoDetailed(size)) { - const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); - NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dest, size, tag.c_str(), tag.size()); + char tag[128]; + size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUMemcpy/", src, size); + NotifyMemInfo(MemBlockFlags::READ, src, size, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dest, size, tag, tagSize); } InvalidateCache(dest, size, GPU_INVALIDATE_HINT); if (!(flags & GPUCopyFlag::DEBUG_NOTIFIED)) @@ -3183,6 +3385,7 @@ std::vector GPUCommon::GetFramebufferList() const { } bool GPUCommon::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { + UpdateUVScaleOffset(); return drawEngineCommon_->GetCurrentSimpleVertices(count, vertices, indices); } @@ -3285,44 +3488,49 @@ size_t GPUCommon::FormatGPUStatsCommon(char *buffer, size_t size) { u32 GPUCommon::CheckGPUFeatures() const { u32 features = 0; if (draw_->GetDeviceCaps().logicOpSupported) { - features |= GPU_SUPPORTS_LOGIC_OP; + features |= GPU_USE_LOGIC_OP; } if (draw_->GetDeviceCaps().anisoSupported) { - features |= GPU_SUPPORTS_ANISOTROPY; + features |= GPU_USE_ANISOTROPY; } if (draw_->GetDeviceCaps().textureNPOTFullySupported) { - features |= GPU_SUPPORTS_TEXTURE_NPOT; + features |= GPU_USE_TEXTURE_NPOT; } if (draw_->GetDeviceCaps().dualSourceBlend) { if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) { - features |= GPU_SUPPORTS_DUALSOURCE_BLEND; + features |= GPU_USE_DUALSOURCE_BLEND; } } if (draw_->GetDeviceCaps().blendMinMaxSupported) { - features |= GPU_SUPPORTS_BLEND_MINMAX; + features |= GPU_USE_BLEND_MINMAX; } if (draw_->GetDeviceCaps().clipDistanceSupported) { - features |= GPU_SUPPORTS_CLIP_DISTANCE; + features |= GPU_USE_CLIP_DISTANCE; } if (draw_->GetDeviceCaps().cullDistanceSupported) { - features |= GPU_SUPPORTS_CULL_DISTANCE; + features |= GPU_USE_CULL_DISTANCE; } if (draw_->GetDeviceCaps().textureDepthSupported) { - features |= GPU_SUPPORTS_DEPTH_TEXTURE; + features |= GPU_USE_DEPTH_TEXTURE; + } + + if (draw_->GetDeviceCaps().depthClampSupported) { + // Some backends always do GPU_USE_ACCURATE_DEPTH, but it's required for depth clamp. + features |= GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH; } bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); if (canClipOrCull || canDiscardVertex) { // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible. - features |= GPU_SUPPORTS_VS_RANGE_CULLING; + features |= GPU_USE_VS_RANGE_CULLING; } if (draw_->GetDeviceCaps().framebufferFetchSupported) { - features |= GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH; + features |= GPU_USE_FRAMEBUFFER_FETCH; } if (draw_->GetShaderLanguageDesc().bitwiseOps) { @@ -3333,5 +3541,51 @@ u32 GPUCommon::CheckGPUFeatures() const { features |= GPU_USE_CLEAR_RAM_HACK; } + // Even without depth clamp, force accurate depth on for some games that break without it. + if (PSP_CoreParameter().compat.flags().DepthRangeHack) { + features |= GPU_USE_ACCURATE_DEPTH; + } + return features; } + +u32 GPUCommon::CheckGPUFeaturesLate(u32 features) const { + // If we already have a 16-bit depth buffer, we don't need to round. + bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; + bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16; + if (!prefer16) { + if (sawExactEqualDepth_ && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + // Exact equal tests tend to have issues unless we use the PSP's depth range. + // We use 24-bit depth virtually everwhere, the fallback is just for safety. + if (prefer24) + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + else + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } else if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) { + // Here we can simulate a 16 bit depth buffer by scaling. + // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else { + // Use fragment rounding on where available otherwise. + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + features |= GPU_ROUND_DEPTH_TO_16BIT; + } + } + + return features; +} + +void GPUCommon::UpdateMSAALevel(Draw::DrawContext *draw) { + int level = g_Config.iMultiSampleLevel; + if (draw && draw->GetDeviceCaps().multiSampleLevelsMask & (1 << level)) { + msaaLevel_ = level; + } else { + // Didn't support the configured level, so revert to 0. + msaaLevel_ = 0; + } +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 8823a52715..28c09034ed 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -71,20 +71,22 @@ struct TransformedVertex { class GPUCommon : public GPUInterface, public GPUDebugInterface { public: GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw); - virtual ~GPUCommon(); + ~GPUCommon(); Draw::DrawContext *GetDrawContext() override { return draw_; } virtual u32 CheckGPUFeatures() const; + void CheckDisplayResized() override; + void CheckConfigChanged() override; + void UpdateCmdInfo(); bool IsReady() override { return true; } - void CancelReady() override { - } + void CancelReady() override {} void Reinitialize() override; void BeginHostFrame() override; @@ -97,7 +99,10 @@ public: interruptsEnabled_ = enable; } - void Resized() override; + void NotifyDisplayResized() override; + void NotifyRenderResized() override; + void NotifyConfigChanged() override; + void DumpNextFrame() override; void ExecuteOp(u32 op, u32 diff) override; @@ -238,8 +243,6 @@ public: return dlQueue; } std::vector GetFramebufferList() const override; - void ClearShaderCache() override {} - void CleanupBeforeUI() override {} s64 GetListTicks(int listid) const override { if (listid >= 0 && listid < DisplayListMaxCount) { @@ -258,10 +261,21 @@ public: fullInfo = reportingFullInfo_; } + int MSAALevel() const { + return msaaLevel_; + } + protected: void DeviceLost() override; void DeviceRestore() override; + void ClearCacheNextFrame() override; + + virtual void CheckRenderResized(); + + // Add additional common features dependent on other features, which may be backend-determined. + u32 CheckGPUFeaturesLate(u32 features) const; + inline bool IsTrianglePrim(GEPrimitiveType prim) const { return prim != GE_PRIM_RECTANGLES && prim > GE_PRIM_LINE_STRIP; } @@ -291,6 +305,7 @@ protected: void UpdateState(GPURunState state); void FastLoadBoneMatrix(u32 target); void FlushImm(); + void DoBlockTransfer(u32 skipDrawReason); // TODO: Unify this. virtual void FinishDeferred() {} @@ -306,6 +321,10 @@ protected: size_t FormatGPUStatsCommon(char *buf, size_t size); + virtual void BuildReportingInfo() = 0; + + void UpdateMSAALevel(Draw::DrawContext *draw); + FramebufferManagerCommon *framebufferManager_ = nullptr; TextureCacheCommon *textureCache_ = nullptr; DrawEngineCommon *drawEngineCommon_ = nullptr; @@ -352,7 +371,10 @@ protected: bool dumpThisFrame_ = false; bool debugRecording_; bool interruptsEnabled_; - bool resized_ = false; + bool displayResized_ = false; + bool renderResized_ = false; + bool configChanged_ = false; + bool sawExactEqualDepth_ = false; DrawType lastDraw_ = DRAW_UNKNOWN; GEPrimitiveType lastPrim_ = GE_PRIM_INVALID; @@ -389,9 +411,10 @@ protected: std::string reportingPrimaryInfo_; std::string reportingFullInfo_; + int msaaLevel_ = 0; + private: void CheckDepthUsage(VirtualFramebuffer *vfb); - void DoBlockTransfer(u32 skipDrawReason); void DoExecuteCall(u32 target); void PopDLQueue(); void CheckDrawSync(); @@ -400,6 +423,7 @@ private: // Debug stats. double timeSteppingStarted_; double timeSpentStepping_; + int lastVsync_ = -1; }; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 5e523a955a..9dc7d82886 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -198,6 +198,9 @@ public: virtual void BeginHostFrame() = 0; virtual void EndHostFrame() = 0; + virtual void CheckDisplayResized() = 0; + virtual void CheckConfigChanged() = 0; + // Draw queue management virtual DisplayList* getList(int listid) = 0; // TODO: Much of this should probably be shared between the different GPU implementations. @@ -254,9 +257,10 @@ public: virtual void DoState(PointerWrap &p) = 0; // Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*. - virtual void Resized() = 0; - virtual void ClearShaderCache() = 0; - virtual void CleanupBeforeUI() = 0; + virtual void NotifyDisplayResized() = 0; + virtual void NotifyRenderResized() = 0; + virtual void NotifyConfigChanged() = 0; + virtual bool FramebufferDirty() = 0; virtual bool FramebufferReallyDirty() = 0; virtual bool BusyDrawing() = 0; diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index 374816fa76..28c13b871a 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -213,7 +213,7 @@ void GPUgstate::FastLoadBoneMatrix(u32 addr) { gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x00FFFFFF); } -void GPUgstate::Restore(u32_le *ptr) { +void GPUgstate::Restore(const u32_le *ptr) { // Not sure what the first 10 values are, exactly, but these seem right. gstate_c.vertexAddr = ptr[5]; gstate_c.indexAddr = ptr[6]; @@ -261,10 +261,7 @@ void GPUgstate::Restore(u32_le *ptr) { } bool vertTypeIsSkinningEnabled(u32 vertType) { - if (g_Config.bSoftwareSkinning) - return false; - else - return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); + return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); } struct GPUStateCache_v0 { @@ -370,3 +367,46 @@ void GPUStateCache::DoState(PointerWrap &p) { Do(p, savedContextVersion); } } + +static const char *const gpuUseFlagNames[32] = { + "GPU_USE_DUALSOURCE_BLEND", + "GPU_USE_LIGHT_UBERSHADER", + "GPU_USE_FRAGMENT_TEST_CACHE", + "GPU_USE_VS_RANGE_CULLING", + "GPU_USE_BLEND_MINMAX", + "GPU_USE_LOGIC_OP", + "N/A", + "GPU_USE_TEXTURE_NPOT", + "GPU_USE_ANISOTROPY", + "GPU_USE_CLEAR_RAM_HACK", + "GPU_USE_INSTANCE_RENDERING", + "GPU_USE_VERTEX_TEXTURE_FETCH", + "GPU_USE_TEXTURE_FLOAT", + "GPU_USE_16BIT_FORMATS", + "GPU_USE_DEPTH_CLAMP", + "GPU_USE_TEXTURE_LOD_CONTROL", + "GPU_USE_DEPTH_TEXTURE", + "GPU_USE_ACCURATE_DEPTH", + "GPU_USE_GS_CULLING", + "N/A", + "GPU_USE_FRAMEBUFFER_FETCH", + "GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT", + "GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT", + "GPU_ROUND_DEPTH_TO_16BIT", + "GPU_USE_CLIP_DISTANCE", + "GPU_USE_CULL_DISTANCE", + "N/A", // bit 26 + "N/A", // bit 27 + "N/A", // bit 28 + "GPU_USE_VIRTUAL_REALITY", + "GPU_USE_SINGLE_PASS_STEREO", + "GPU_USE_SIMPLE_STEREO_PERSPECTIVE", +}; + +const char *GpuUseFlagToString(int useFlag) { + if ((u32)useFlag < 32) { + return gpuUseFlagNames[useFlag]; + } else { + return "N/A"; + } +} diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 15b837e5ba..e95c13558b 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -445,7 +445,7 @@ struct GPUgstate { void Reset(); void Save(u32_le *ptr); - void Restore(u32_le *ptr); + void Restore(const u32_le *ptr); }; bool vertTypeIsSkinningEnabled(u32 vertType); @@ -470,39 +470,44 @@ struct UVScale { // location. Sometimes we need to take things into account in multiple places, it helps // to centralize into flags like this. They're also fast to check since the cache line // will be hot. +// NOTE: Do not forget to update the string array at the end of GPUState.cpp! enum { - GPU_SUPPORTS_DUALSOURCE_BLEND = FLAG_BIT(0), + GPU_USE_DUALSOURCE_BLEND = FLAG_BIT(0), GPU_USE_LIGHT_UBERSHADER = FLAG_BIT(1), GPU_USE_FRAGMENT_TEST_CACHE = FLAG_BIT(2), - GPU_SUPPORTS_VS_RANGE_CULLING = FLAG_BIT(3), - GPU_SUPPORTS_BLEND_MINMAX = FLAG_BIT(4), - GPU_SUPPORTS_LOGIC_OP = FLAG_BIT(5), - GPU_USE_DEPTH_RANGE_HACK = FLAG_BIT(6), - // Free bit: 7 - GPU_SUPPORTS_ANISOTROPY = FLAG_BIT(8), + GPU_USE_VS_RANGE_CULLING = FLAG_BIT(3), + GPU_USE_BLEND_MINMAX = FLAG_BIT(4), + GPU_USE_LOGIC_OP = FLAG_BIT(5), + // Bit 6 is free. + GPU_USE_TEXTURE_NPOT = FLAG_BIT(7), + GPU_USE_ANISOTROPY = FLAG_BIT(8), GPU_USE_CLEAR_RAM_HACK = FLAG_BIT(9), - GPU_SUPPORTS_INSTANCE_RENDERING = FLAG_BIT(10), - GPU_SUPPORTS_VERTEX_TEXTURE_FETCH = FLAG_BIT(11), - GPU_SUPPORTS_TEXTURE_FLOAT = FLAG_BIT(12), - GPU_SUPPORTS_16BIT_FORMATS = FLAG_BIT(13), - GPU_SUPPORTS_DEPTH_CLAMP = FLAG_BIT(14), - // Free bit: 15 - GPU_SUPPORTS_DEPTH_TEXTURE = FLAG_BIT(16), - GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17), - GPU_SUPPORTS_GS_CULLING = FLAG_BIT(18), // Geometry shader - // Free bit: 19 - GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), + GPU_USE_INSTANCE_RENDERING = FLAG_BIT(10), + GPU_USE_VERTEX_TEXTURE_FETCH = FLAG_BIT(11), + GPU_USE_TEXTURE_FLOAT = FLAG_BIT(12), + GPU_USE_16BIT_FORMATS = FLAG_BIT(13), + GPU_USE_DEPTH_CLAMP = FLAG_BIT(14), + GPU_USE_TEXTURE_LOD_CONTROL = FLAG_BIT(15), + GPU_USE_DEPTH_TEXTURE = FLAG_BIT(16), + GPU_USE_ACCURATE_DEPTH = FLAG_BIT(17), + GPU_USE_GS_CULLING = FLAG_BIT(18), // Geometry shader + // Bit 19 free. + GPU_USE_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer - GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24), - // Free bits: 25-27 - GPU_SUPPORTS_TEXTURE_NPOT = FLAG_BIT(28), - GPU_SUPPORTS_CLIP_DISTANCE = FLAG_BIT(29), - GPU_SUPPORTS_CULL_DISTANCE = FLAG_BIT(30), - GPU_PREFER_REVERSE_COLOR_ORDER = FLAG_BIT(31), + GPU_USE_CLIP_DISTANCE = FLAG_BIT(24), + GPU_USE_CULL_DISTANCE = FLAG_BIT(25), + + // VR flags (reserved or in-use) + GPU_USE_VIRTUAL_REALITY = FLAG_BIT(29), + GPU_USE_SINGLE_PASS_STEREO = FLAG_BIT(30), + GPU_USE_SIMPLE_STEREO_PERSPECTIVE = FLAG_BIT(31), }; +// Note that this take a flag index, not the bit value. +const char *GpuUseFlagToString(int useFlag); + struct KnownVertexBounds { u16 minU; u16 minV; @@ -519,8 +524,9 @@ enum class SubmitType { }; struct GPUStateCache { - bool Supports(u32 flags) { return (featureFlags & flags) != 0; } // Return true if ANY of flags are true. - bool SupportsAll(u32 flags) { return (featureFlags & flags) == flags; } // Return true if ALL flags are true. + bool Use(u32 flags) { return (useFlags_ & flags) != 0; } // Return true if ANY of flags are true. + bool UseAll(u32 flags) { return (useFlags_ & flags) == flags; } // Return true if ALL flags are true. + uint64_t GetDirtyUniforms() { return dirty & DIRTY_ALL_UNIFORMS; } void Dirty(u64 what) { dirty |= what; @@ -560,9 +566,33 @@ struct GPUStateCache { Dirty(DIRTY_FRAGMENTSHADER_STATE | (is3D ? DIRTY_MIPBIAS : 0)); } } + void SetTextureIsArray(bool isArrayTexture) { // VK only + if (arrayTexture != isArrayTexture) { + arrayTexture = isArrayTexture; + Dirty(DIRTY_FRAGMENTSHADER_STATE); + } + } + void SetTextureIsBGRA(bool isBGRA) { + if (bgraTexture != isBGRA) { + bgraTexture = isBGRA; + Dirty(DIRTY_FRAGMENTSHADER_STATE); + } + } + void SetUseFlags(u32 newFlags) { + if (newFlags != useFlags_) { + useFlags_ = newFlags; + // Recompile shaders and stuff? + } + } - u32 featureFlags; + // When checking for a single flag, use Use()/UseAll(). + u32 GetUseFlags() const { + return useFlags_; + } +private: + u32 useFlags_; +public: u32 vertexAddr; u32 indexAddr; u32 offsetAddr; @@ -581,6 +611,7 @@ struct GPUStateCache { bool bgraTexture; bool needShaderTexClamp; + bool arrayTexture; float morphWeights[8]; u32 deferredVertTypeDirty; diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index a645b5bc2b..af8131958b 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -525,9 +525,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { case GE_CMD_TRANSFERSRCW: { u32 xferSrc = (gstate.transfersrc & 0x00FFFFFF) | ((data & 0xFF0000) << 8); - u32 xferSrcW = data & 0x3FF; - if (data & ~0xFF03FF) - snprintf(buffer, bufsize, "Block transfer src: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferSrcW, xferSrc, data & ~0xFF03FF); + u32 xferSrcW = (data & 0x400) != 0 ? 0x400 : (data & 0x3FF); + u32 validMask = (data & 0x400) != 0 ? 0xFF0400 : 0xFF03FF; + if (data & ~validMask) + snprintf(buffer, bufsize, "Block transfer src: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferSrcW, xferSrc, data & ~validMask); else snprintf(buffer, bufsize, "Block transfer src: high=%02x, w=%d (addr %08x)", data >> 16, xferSrcW, xferSrc); break; @@ -546,9 +547,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { case GE_CMD_TRANSFERDSTW: { u32 xferDst = (gstate.transferdst & 0x00FFFFFF) | ((data & 0xFF0000) << 8); - u32 xferDstW = data & 0x3FF; - if (data & ~0xFF03FF) - snprintf(buffer, bufsize, "Block transfer dst: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferDstW, xferDst, data & ~0xFF03FF); + u32 xferDstW = (data & 0x400) != 0 ? 0x400 : (data & 0x3FF); + u32 validMask = (data & 0x400) != 0 ? 0xFF0400 : 0xFF03FF; + if (data & ~validMask) + snprintf(buffer, bufsize, "Block transfer dst: high=%02x, w=%d (addr %08x, extra %x)", data >> 16, xferDstW, xferDst, data & ~validMask); else snprintf(buffer, bufsize, "Block transfer dst: high=%02x, w=%d (addr %08x)", data >> 16, xferDstW, xferDst); break; diff --git a/GPU/Math3D.cpp b/GPU/Math3D.cpp index ecb959ec2c..fec4c887bd 100644 --- a/GPU/Math3D.cpp +++ b/GPU/Math3D.cpp @@ -50,8 +50,7 @@ Vec2 Vec2::WithLength(const float l) const } template<> -float Vec2::Distance2To(Vec2 &other) -{ +float Vec2::Distance2To(const Vec2 &other) const { return Vec2(other-(*this)).Length2(); } @@ -99,8 +98,7 @@ Vec3 Vec3::WithLength(const float l) const } template<> -float Vec3::Distance2To(Vec3 &other) -{ +float Vec3::Distance2To(const Vec3 &other) const { return Vec3(other-(*this)).Length2(); } @@ -231,8 +229,7 @@ Vec3Packed Vec3Packed::WithLength(const float l) const } template<> -float Vec3Packed::Distance2To(Vec3Packed &other) -{ +float Vec3Packed::Distance2To(const Vec3Packed &other) const { return Vec3Packed(other-(*this)).Length2(); } @@ -279,8 +276,7 @@ Vec4 Vec4::WithLength(const float l) const } template<> -float Vec4::Distance2To(Vec4 &other) -{ +float Vec4::Distance2To(const Vec4 &other) const { return Vec4(other-(*this)).Length2(); } diff --git a/GPU/Math3D.h b/GPU/Math3D.h index d6514aa1b0..88a62c72da 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -145,7 +145,7 @@ public: float Length() const; void SetLength(const float l); Vec2 WithLength(const float l) const; - float Distance2To(Vec2 &other); + float Distance2To(const Vec2 &other) const; Vec2 Normalized() const; float Normalize(); // returns the previous length, which is often useful @@ -310,7 +310,7 @@ public: float Length() const; void SetLength(const float l); Vec3 WithLength(const float l) const; - float Distance2To(Vec3 &other); + float Distance2To(const Vec3 &other) const; Vec3 Normalized(bool useSSE4 = false) const; Vec3 NormalizedOr001(bool useSSE4 = false) const; float Normalize(); // returns the previous length, which is often useful @@ -478,7 +478,7 @@ public: float Length() const; void SetLength(const float l); Vec3Packed WithLength(const float l) const; - float Distance2To(Vec3Packed &other); + float Distance2To(const Vec3Packed &other) const; Vec3Packed Normalized() const; float Normalize(); // returns the previous length, which is often useful @@ -674,7 +674,7 @@ public: float Length() const; void SetLength(const float l); Vec4 WithLength(const float l) const; - float Distance2To(Vec4 &other); + float Distance2To(const Vec4 &other) const; Vec4 Normalized() const; float Normalize(); // returns the previous length, which is often useful @@ -898,7 +898,8 @@ inline void Vec3ByMatrix43(float vecOut[3], const float v[3], const float m[12]) vecOut[1] = vectorGetByIndex<1>(sum); vecOut[2] = vectorGetByIndex<2>(sum); #elif PPSSPP_ARCH(ARM64_NEON) - float32x4_t sum = Vec3ByMatrix43Internal(vld1q_f32(v), m); + float vecIn[4] = {v[0], v[1], v[2], 1.0f}; + float32x4_t sum = Vec3ByMatrix43Internal(vld1q_f32(vecIn), m); vecOut[0] = vgetq_lane_f32(sum, 0); vecOut[1] = vgetq_lane_f32(sum, 1); vecOut[2] = vgetq_lane_f32(sum, 2); @@ -957,7 +958,8 @@ inline void Vec3ByMatrix44(float vecOut[4], const float v[3], const float m[16]) __m128 sum = Vec3ByMatrix44Internal(x, y, z, m); _mm_storeu_ps(vecOut, sum); #elif PPSSPP_ARCH(ARM64_NEON) - float32x4_t sum = Vec3ByMatrix44Internal(vld1q_f32(v), m); + float vecIn[4] = {v[0], v[1], v[2], 1.0f}; + float32x4_t sum = Vec3ByMatrix44Internal(vld1q_f32(vecIn), m); vst1q_f32(vecOut, sum); #else vecOut[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + m[12]; diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 9a008e6658..1978d32edc 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -27,6 +27,9 @@ #include "GPU/Software/Rasterizer.h" #include "GPU/Software/RasterizerRectangle.h" +// Sometimes useful for debugging. +static constexpr bool FORCE_SINGLE_THREAD = false; + using namespace Rasterizer; struct BinWaitable : public Waitable { @@ -166,9 +169,12 @@ void BinManager::UpdateState() { if (HasDirty(SoftDirty::PIXEL_ALL | SoftDirty::SAMPLER_ALL | SoftDirty::RAST_ALL)) { if (states_.Full()) Flush("states"); + creatingState_ = true; stateIndex_ = (uint16_t)states_.Push(RasterizerState()); - ComputeRasterizerState(&states_[stateIndex_]); + // When new funcs are compiled, we need to flush if WX exclusive. + ComputeRasterizerState(&states_[stateIndex_], this); states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable; + creatingState_ = false; ClearDirty(SoftDirty::PIXEL_ALL | SoftDirty::SAMPLER_ALL | SoftDirty::RAST_ALL); } @@ -215,7 +221,7 @@ void BinManager::UpdateState() { // Disallow threads when rendering to the target, even offset. bool selfRender = HasTextureWrite(state); - int newMaxTasks = selfRender ? 1 : g_threadManager.GetNumLooperThreads(); + int newMaxTasks = selfRender || FORCE_SINGLE_THREAD ? 1 : g_threadManager.GetNumLooperThreads(); if (newMaxTasks > MAX_POSSIBLE_TASKS) newMaxTasks = MAX_POSSIBLE_TASKS; // We don't want to overlap wrong, so flush any pending. @@ -254,6 +260,40 @@ bool BinManager::HasTextureWrite(const RasterizerState &state) { return false; } +bool BinManager::IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item) { + if (item.type != BinItemType::SPRITE && item.type != BinItemType::RECT) + return false; + if (state.textureProj || state.maxTexLevel > 0) + return false; + + // Only possible if the texture is 1:1. + if ((state.texaddr[0] & 0x0F1FFFFF) != (gstate.getFrameBufAddress() & 0x0F1FFFFF)) + return false; + int bufferPixelWidth = BufferFormatBytesPerPixel(state.pixelID.FBFormat()); + int texturePixelWidth = textureBitsPerPixel[state.samplerID.texfmt] / 8; + if (bufferPixelWidth != texturePixelWidth) + return false; + + Vec4f tc = Vec4f(item.v0.texturecoords.x, item.v0.texturecoords.y, item.v1.texturecoords.x, item.v1.texturecoords.y); + if (state.throughMode) { + // Already at texels, convert to screen. + tc = tc * SCREEN_SCALE_FACTOR; + } else { + // Need to also multiply by width/height in transform mode. + int w = state.samplerID.cached.sizes[0].w * SCREEN_SCALE_FACTOR; + int h = state.samplerID.cached.sizes[0].h * SCREEN_SCALE_FACTOR; + tc = tc * Vec4f(w, h, w, h); + } + + Vec4 tci = tc.Cast(); + if (tci.x != item.v0.screenpos.x || tci.y != item.v0.screenpos.y) + return false; + if (tci.z != item.v1.screenpos.x || tci.w != item.v1.screenpos.y) + return false; + + return true; +} + void BinManager::MarkPendingReads(const Rasterizer::RasterizerState &state) { if (!state.enableTextures) return; @@ -293,7 +333,7 @@ void BinManager::MarkPendingWrites(const Rasterizer::RasterizerState &state) { pendingWrites_[1].Expand(gstate.getDepthBufAddress() & mirrorMask, 2, gstate.DepthBufStride(), scissorTL, scissorBR); } -inline void BinDirtyRange::Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, DrawingCoords &tl, DrawingCoords &br) { +inline void BinDirtyRange::Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, const DrawingCoords &tl, const DrawingCoords &br) { const uint32_t w = br.x - tl.x + 1; const uint32_t h = br.y - tl.y + 1; @@ -348,6 +388,7 @@ void BinManager::AddTriangle(const VertexData &v0, const VertexData &v1, const V if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::TRIANGLE, stateIndex_, range, v0, v1, v2 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, v2); Expand(range); } @@ -359,6 +400,7 @@ void BinManager::AddClearRect(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::CLEAR_RECT, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, true); Expand(range); } @@ -370,6 +412,7 @@ void BinManager::AddRect(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::RECT, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, true); Expand(range); } @@ -381,6 +424,7 @@ void BinManager::AddSprite(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::SPRITE, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, true); Expand(range); } @@ -392,6 +436,7 @@ void BinManager::AddLine(const VertexData &v0, const VertexData &v1) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::LINE, stateIndex_, range, v0, v1 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0, v1, false); Expand(range); } @@ -403,6 +448,7 @@ void BinManager::AddPoint(const VertexData &v0) { if (queue_.Full()) Drain(); queue_.Push(BinItem{ BinItemType::POINT, stateIndex_, range, v0 }); + CalculateRasterStateFlags(&states_[stateIndex_], v0); Expand(range); } @@ -418,6 +464,14 @@ void BinManager::Drain(bool flushing) { ScreenCoords tl(0, 0, 0); ScreenCoords br(1024 * SCREEN_SCALE_FACTOR, 1024 * SCREEN_SCALE_FACTOR, 0); + if (pendingOverlap_ && maxTasks_ == 1 && flushing && queue_.Size() == 1 && !FORCE_SINGLE_THREAD) { + // If the drawing is 1:1, we can potentially use threads. It's worth checking. + const auto &item = queue_.PeekNext(); + const auto &state = states_[item.stateIndex]; + if (IsExactSelfRender(state, item)) + maxTasks_ = std::min(g_threadManager.GetNumLooperThreads(), MAX_POSSIBLE_TASKS); + } + taskRanges_.clear(); if (h2 >= 18 && w2 >= h2 * 4) { int bin_w = std::max(4, (w2 + maxTasks_ - 1) / maxTasks_) * SCREEN_SCALE_FACTOR * 2; @@ -438,6 +492,10 @@ void BinManager::Drain(bool flushing) { tasksSplit_ = true; } + // Let's try to optimize states, if we can. + OptimizePendingStates(pendingStateIndex_, stateIndex_); + pendingStateIndex_ = stateIndex_; + if (taskRanges_.size() <= 1) { PROFILE_THIS_SCOPE("bin_drain_single"); while (!queue_.Empty()) { @@ -510,6 +568,9 @@ void BinManager::Flush(const char *reason) { while (cluts_.Size() > 1) cluts_.SkipNext(); + Rasterizer::FlushJit(); + Sampler::FlushJit(); + queueRange_.x1 = 0x7FFFFFFF; queueRange_.y1 = 0x7FFFFFFF; queueRange_.x2 = 0; @@ -533,6 +594,22 @@ void BinManager::Flush(const char *reason) { } } +void BinManager::OptimizePendingStates(uint16_t first, uint16_t last) { + // We can sometimes hit this when compiling new funcs while creating a state. + // At that point, the state isn't loaded fully yet, so don't touch it. + if (creatingState_ && last == stateIndex_) { + if (first == last) + return; + last--; + } + + int count = (QUEUED_STATES + last - first) % QUEUED_STATES + 1; + for (int i = 0; i < count; ++i) { + size_t pos = (first + i) % QUEUED_STATES; + OptimizeRasterState(&states_[pos]); + } +} + bool BinManager::HasPendingWrite(uint32_t start, uint32_t stride, uint32_t w, uint32_t h) { // We can only write to VRAM. if (!Memory::IsVRAMAddress(start)) @@ -681,6 +758,9 @@ void BinManager::Expand(const BinCoords &range) { queueRange_.y2 = std::max(queueRange_.y2, range.y2); if (maxTasks_ == 1 || (queueRange_.y2 - queueRange_.y1 >= 224 * SCREEN_SCALE_FACTOR && enqueues_ < 36 * maxTasks_)) { - Drain(); + if (pendingOverlap_) + Flush("expand"); + else + Drain(); } } diff --git a/GPU/Software/BinManager.h b/GPU/Software/BinManager.h index d874f0d3c8..116fb19e27 100644 --- a/GPU/Software/BinManager.h +++ b/GPU/Software/BinManager.h @@ -177,7 +177,7 @@ struct BinDirtyRange { uint32_t widthBytes; uint32_t height; - void Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, DrawingCoords &tl, DrawingCoords &br); + void Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, const DrawingCoords &tl, const DrawingCoords &br); }; class BinManager { @@ -261,6 +261,8 @@ private: std::unordered_map pendingReads_; bool pendingOverlap_ = false; + bool creatingState_ = false; + uint16_t pendingStateIndex_ = 0; std::unordered_map flushReasonTimes_; std::unordered_map lastFlushReasonTimes_; @@ -273,6 +275,8 @@ private: void MarkPendingReads(const Rasterizer::RasterizerState &state); void MarkPendingWrites(const Rasterizer::RasterizerState &state); bool HasTextureWrite(const Rasterizer::RasterizerState &state); + bool IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item); + void OptimizePendingStates(uint16_t first, uint16_t last); BinCoords Scissor(BinCoords range); BinCoords Range(const VertexData &v0, const VertexData &v1, const VertexData &v2); BinCoords Range(const VertexData &v0, const VertexData &v1); diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index e9ad7ec5b4..2d96b1f24c 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -49,7 +49,19 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, return (vert.clippos.x * A + vert.clippos.y * B + vert.clippos.z * C + vert.clippos.w * D); } -#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \ +inline void clip_interpolate(ClipVertexData &dest, float t, const ClipVertexData &a, const ClipVertexData &b) { + bool outsideRange = false; + dest.Lerp(t, a, b); + dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos, &outsideRange); + dest.v.clipw = dest.clippos.w; + + // If the clipped coordinate is outside range, then we throw it away. + // This prevents a lot of inversions that shouldn't be drawn. + if (outsideRange) + dest.v.screenpos.x = 0x7FFFFFFF; +} + +#define CLIP_POLY( PLANE_BIT, A, B, C, D ) \ { \ if (mask & PLANE_BIT) { \ int idxPrev = inlist[0]; \ @@ -64,15 +76,17 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, outlist[outcount++] = idxPrev; \ } \ \ - if (different_signs(dp, dpPrev)) { \ + /* Skipping w sign mismatches avoids inversions, but is incorrect. See #16131. */ \ + /* For now, it's better to avoid inversions as they usually are undesired. */ \ + if (different_signs(dp, dpPrev)) { \ + auto &vert = Vertices[numVertices++]; \ if (dp < 0) { \ float t = dp / (dp - dpPrev); \ - Vertices[numVertices++]->Lerp(t, *Vertices[idx], *Vertices[idxPrev]); \ + clip_interpolate(*vert, t, *Vertices[idx], *Vertices[idxPrev]); \ } else { \ float t = dpPrev / (dpPrev - dp); \ - Vertices[numVertices++]->Lerp(t, *Vertices[idxPrev], *Vertices[idx]); \ + clip_interpolate(*vert, t, *Vertices[idxPrev], *Vertices[idx]); \ } \ - clipped = true; \ outlist[outcount++] = numVertices - 1; \ } \ \ @@ -101,8 +115,7 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, if (mask0 & PLANE_BIT) { \ if (dp0 < 0) { \ float t = dp1 / (dp1 - dp0); \ - Vertices[0]->Lerp(t, *Vertices[1], *Vertices[0]); \ - clipped = true; \ + clip_interpolate(*Vertices[0], t, *Vertices[1], *Vertices[0]); \ } \ } \ dp0 = clip_dotprod(*Vertices[0], A, B, C, D ); \ @@ -110,8 +123,7 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C, if (mask1 & PLANE_BIT) { \ if (dp1 < 0) { \ float t = dp1 / (dp1- dp0); \ - Vertices[1]->Lerp(t, *Vertices[1], *Vertices[0]); \ - clipped = true; \ + clip_interpolate(*Vertices[1], t, *Vertices[1], *Vertices[0]); \ } \ } \ } \ @@ -203,15 +215,26 @@ void ProcessRect(const ClipVertexData &v0, const ClipVertexData &v1, BinManager else if (outsidePos >= 2 || outsideNeg >= 2) return; - if (v0.v.fogdepth != v1.v.fogdepth) { + bool splitFog = v0.v.fogdepth != v1.v.fogdepth; + if (splitFog) { + // If they match the same 1/255, we can consider the fog flat. Seen in Resistance. + // More efficient if we can avoid splitting. + static constexpr float foghalfstep = 0.5f / 255.0f; + if (v1.v.fogdepth - foghalfstep <= v0.v.fogdepth && v1.v.fogdepth + foghalfstep >= v0.v.fogdepth) + splitFog = false; + } + if (splitFog) { // Rectangles seem to always use nearest along X for fog depth, but reversed. // TODO: Check exactness of middle. VertexData vhalf0 = v1.v; vhalf0.screenpos.x = v0.v.screenpos.x + (v1.v.screenpos.x - v0.v.screenpos.x) / 2; + vhalf0.texturecoords.x = v0.v.texturecoords.x + (v1.v.texturecoords.x - v0.v.texturecoords.x) / 2; VertexData vhalf1 = v1.v; vhalf1.screenpos.x = v0.v.screenpos.x + (v1.v.screenpos.x - v0.v.screenpos.x) / 2; vhalf1.screenpos.y = v0.v.screenpos.y; + vhalf1.texturecoords.x = v0.v.texturecoords.x + (v1.v.texturecoords.x - v0.v.texturecoords.x) / 2; + vhalf1.texturecoords.y = v0.v.texturecoords.y; VertexData vrev1 = v1.v; vrev1.fogdepth = v0.v.fogdepth; @@ -283,17 +306,11 @@ void ProcessLine(const ClipVertexData &v0, const ClipVertexData &v1, BinManager ClipVertexData ClippedVertices[2] = { v0, v1 }; ClipVertexData *Vertices[2] = { &ClippedVertices[0], &ClippedVertices[1] }; - bool clipped = false; CLIP_LINE(CLIP_NEG_Z_BIT, 0, 0, 1, 1); ClipVertexData data[2] = { *Vertices[0], *Vertices[1] }; - if (clipped) { - data[0].v.screenpos = TransformUnit::ClipToScreen(data[0].clippos); - data[1].v.screenpos = TransformUnit::ClipToScreen(data[1].clippos); - data[0].v.clipw = data[0].clippos.w; - data[1].v.clipw = data[1].clippos.w; - } - binner.AddLine(data[0].v, data[1].v); + if (!data[0].OutsideRange() && !data[1].OutsideRange()) + binner.AddLine(data[0].v, data[1].v); } void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const ClipVertexData &v2, const ClipVertexData &provoking, BinManager &binner) { @@ -352,7 +369,6 @@ void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const C int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG }; int numIndices = 3; - bool clipped = false; for (int i = 0; i < 3; i += 3) { int vlist[2][2*6+1]; @@ -370,7 +386,7 @@ void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const C indices[2] = SKIP_FLAG; // The PSP only clips on negative Z (importantly, regardless of viewport.) - POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); + CLIP_POLY(CLIP_NEG_Z_BIT, 0, 0, 1, 1); // transform the poly in inlist into triangles indices[0] = inlist[0]; @@ -388,14 +404,9 @@ void ProcessTriangle(const ClipVertexData &v0, const ClipVertexData &v1, const C ClipVertexData &subv0 = *Vertices[indices[i + 0]]; ClipVertexData &subv1 = *Vertices[indices[i + 1]]; ClipVertexData &subv2 = *Vertices[indices[i + 2]]; - if (clipped) { - subv0.v.screenpos = TransformUnit::ClipToScreen(subv0.clippos); - subv1.v.screenpos = TransformUnit::ClipToScreen(subv1.clippos); - subv2.v.screenpos = TransformUnit::ClipToScreen(subv2.clippos); - subv0.v.clipw = subv0.clippos.w; - subv1.v.clipw = subv1.clippos.w; - subv2.v.clipw = subv2.clippos.w; - } + + if (subv0.OutsideRange() || subv1.OutsideRange() | subv2.OutsideRange()) + continue; if (gstate.getShadeMode() == GE_SHADE_FLAT) { // So that the order of clipping doesn't matter... diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp index f47ea6656a..97e84b6807 100644 --- a/GPU/Software/DrawPixel.cpp +++ b/GPU/Software/DrawPixel.cpp @@ -20,6 +20,7 @@ #include "Common/Data/Convert/ColorConv.h" #include "Core/Config.h" #include "GPU/GPUState.h" +#include "GPU/Software/BinManager.h" #include "GPU/Software/DrawPixel.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/Rasterizer.h" @@ -36,6 +37,10 @@ void Init() { jitCache = new PixelJitCache(); } +void FlushJit() { + jitCache->Flush(); +} + void Shutdown() { delete jitCache; jitCache = nullptr; @@ -703,8 +708,8 @@ void SOFTRAST_CALL DrawSinglePixel(int x, int y, int z, int fog, Vec4IntArg colo SetPixelColor(fbFormat, pixelID.cached.framebufStride, x, y, new_color, old_color, targetWriteMask); } -SingleFunc GetSingleFunc(const PixelFuncID &id) { - SingleFunc jitted = jitCache->GetSingle(id); +SingleFunc GetSingleFunc(const PixelFuncID &id, BinManager *binner) { + SingleFunc jitted = jitCache->GetSingle(id, binner); if (jitted) { return jitted; } @@ -739,13 +744,17 @@ SingleFunc PixelJitCache::GenericSingle(const PixelFuncID &id) { return nullptr; } +thread_local PixelJitCache::LastCache PixelJitCache::lastSingle_; + // 256k should be plenty of space for plenty of variations. -PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4) { +PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4), cache_(64) { + lastSingle_.gen = -1; } void PixelJitCache::Clear() { + clearGen_++; CodeBlock::Clear(); - cache_.clear(); + cache_.Clear(); addresses_.clear(); constBlendHalf_11_4s_ = nullptr; @@ -771,28 +780,70 @@ std::string PixelJitCache::DescribeCodePtr(const u8 *ptr) { return CodeBlock::DescribeCodePtr(ptr); } -SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id) { - std::lock_guard guard(jitCacheLock); +void PixelJitCache::Flush() { + std::unique_lock guard(jitCacheLock); + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } + compileQueue_.clear(); +} - auto it = cache_.find(id); - if (it != cache_.end()) { - return it->second; +SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, BinManager *binner) { + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + + const size_t key = std::hash()(id); + if (lastSingle_.Match(key, clearGen_)) + return lastSingle_.func; + + std::unique_lock guard(jitCacheLock); + auto it = cache_.Get(key); + if (it != nullptr) { + lastSingle_.Set(key, it, clearGen_); + return it; } + if (!binner) { + // Can't compile, let's try to do it later when there's an opportunity. + compileQueue_.insert(id); + return nullptr; + } + + guard.unlock(); + binner->Flush("compile"); + guard.lock(); + + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } + compileQueue_.clear(); + + // Might've been in the queue. + if (!cache_.Get(key)) + Compile(id); + + it = cache_.Get(key); + lastSingle_.Set(key, it, clearGen_); + return it; +} + +void PixelJitCache::Compile(const PixelFuncID &id) { // x64 is typically 200-500 bytes, but let's be safe. if (GetSpaceLeft() < 65536) { Clear(); } #if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP) - if (g_Config.bSoftwareRenderingJit) { - addresses_[id] = GetCodePointer(); - SingleFunc func = CompileSingle(id); - cache_[id] = func; - return func; - } + addresses_[id] = GetCodePointer(); + SingleFunc func = CompileSingle(id); + cache_.Insert(std::hash()(id), func); #endif - return nullptr; } void ComputePixelBlendState(PixelBlendState &state, const PixelFuncID &id) { diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h index 65f6fa1ec5..d72c04a744 100644 --- a/GPU/Software/DrawPixel.h +++ b/GPU/Software/DrawPixel.h @@ -22,10 +22,14 @@ #include #include #include +#include +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/Math3D.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" +class BinManager; + namespace Rasterizer { // Our std::unordered_map argument will ignore the alignment attribute, but that doesn't matter. @@ -36,9 +40,10 @@ namespace Rasterizer { #endif typedef void (SOFTRAST_CALL *SingleFunc)(int x, int y, int z, int fog, Vec4IntArg color_in, const PixelFuncID &pixelID); -SingleFunc GetSingleFunc(const PixelFuncID &id); +SingleFunc GetSingleFunc(const PixelFuncID &id, BinManager *binner); void Init(); +void FlushJit(); void Shutdown(); bool CheckDepthTestPassed(GEComparison func, int x, int y, int stride, u16 z); @@ -60,13 +65,15 @@ public: PixelJitCache(); // Returns a pointer to the code to run. - SingleFunc GetSingle(const PixelFuncID &id); + SingleFunc GetSingle(const PixelFuncID &id, BinManager *binner); SingleFunc GenericSingle(const PixelFuncID &id); void Clear() override; + void Flush(); std::string DescribeCodePtr(const u8 *ptr) override; private: + void Compile(const PixelFuncID &id); SingleFunc CompileSingle(const PixelFuncID &id); RegCache::Reg GetPixelID(); @@ -102,8 +109,27 @@ private: bool Jit_ConvertFrom5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); bool Jit_ConvertFrom4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha); - std::unordered_map cache_; + struct LastCache { + size_t key; + SingleFunc func; + int gen = -1; + + bool Match(size_t k, int g) const { + return key == k && gen == g; + } + + void Set(size_t k, SingleFunc f, int g) { + key = k; + func = f; + gen = g; + } + }; + + DenseHashMap cache_; std::unordered_map addresses_; + std::unordered_set compileQueue_; + int clearGen_ = 0; + static thread_local LastCache lastSingle_; const u8 *constBlendHalf_11_4s_ = nullptr; const u8 *constBlendInvert_11_4s_ = nullptr; diff --git a/GPU/Software/DrawPixelX86.cpp b/GPU/Software/DrawPixelX86.cpp index 53f9c94279..2ba334df94 100644 --- a/GPU/Software/DrawPixelX86.cpp +++ b/GPU/Software/DrawPixelX86.cpp @@ -31,19 +31,6 @@ using namespace Gen; namespace Rasterizer { -template -static bool Accessible(const T *t1, const T *t2) { - ptrdiff_t diff = (const uint8_t *)t1 - (const uint8_t *)t2; - return diff > -0x7FFFFFE0 && diff < 0x7FFFFFE0; -} - -template -static OpArg MAccessibleDisp(X64Reg r, const T *tbase, const T *t) { - _assert_(Accessible(tbase, t)); - ptrdiff_t diff = (const uint8_t *)t - (const uint8_t *)tbase; - return MDisp(r, (int)diff); -} - SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) { // Setup the reg cache and disallow spill for arguments. regCache_.SetupABI({ @@ -55,11 +42,12 @@ SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) { RegCache::GEN_ARG_ID, }); - BeginWrite(); + BeginWrite(64); Describe("Init"); WriteConstantPool(id); const u8 *resetPos = AlignCode16(); + EndWrite(); bool success = true; #if PPSSPP_PLATFORM(WINDOWS) diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 32596989fe..82315b1b20 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -24,7 +24,7 @@ namespace Lighting { -static inline Vec3f GetLightVec(u32 lparams[12], int light) { +static inline Vec3f GetLightVec(const u32 lparams[12], int light) { #if defined(_M_SSE) && !PPSSPP_ARCH(X86) __m128i values = _mm_loadu_si128((__m128i *)&lparams[3 * light]); __m128i from24 = _mm_slli_epi32(values, 8); diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index d59c1fb0cf..4b9ed61d27 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -93,15 +93,15 @@ static inline Vec4 Interpolate(const float &c0, const float &c1, const fl return Interpolate(c0, c1, c2, w0.Cast(), w1.Cast(), w2.Cast(), wsum_recip); } -void ComputeRasterizerState(RasterizerState *state) { +void ComputeRasterizerState(RasterizerState *state, BinManager *binner) { ComputePixelFuncID(&state->pixelID); - state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID); + state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID, binner); state->enableTextures = gstate.isTextureMapEnabled() && !state->pixelID.clearMode; if (state->enableTextures) { ComputeSamplerID(&state->samplerID); - state->linear = Sampler::GetLinearFunc(state->samplerID); - state->nearest = Sampler::GetNearestFunc(state->samplerID); + state->linear = Sampler::GetLinearFunc(state->samplerID, binner); + state->nearest = Sampler::GetNearestFunc(state->samplerID, binner); // Since the definitions are the same, just force this setting using the func pointer. if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { @@ -132,13 +132,18 @@ void ComputeRasterizerState(RasterizerState *state) { state->textureProj = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; if (state->textureProj) { // We may be able to optimize this off. This is actually kinda common. - if (gstate.tgenMatrix[2] == 0.0f && gstate.tgenMatrix[5] == 0.0f && gstate.tgenMatrix[8] == 0.0f && gstate.tgenMatrix[11] == 1.0f) { + const bool qZeroST = gstate.tgenMatrix[2] == 0.0f && gstate.tgenMatrix[5] == 0.0f; + const bool qZeroQ = gstate.tgenMatrix[8] == 0.0f; + + // Two common cases: the source q factor is zero, OR source is UV. + const bool qFactorZero = gstate.getUVProjMode() == GE_PROJMAP_UV; + if (qZeroST && (qZeroQ || qFactorZero) && gstate.tgenMatrix[11] == 1.0f) { state->textureProj = false; } } } - state->shadeGouraud = gstate.getShadeMode() == GE_SHADE_GOURAUD; + state->shadeGouraud = !gstate.isModeClear() && gstate.getShadeMode() == GE_SHADE_GOURAUD; state->throughMode = gstate.isModeThrough(); state->antialiasLines = gstate.isAntiAliasEnabled(); @@ -150,66 +155,340 @@ void ComputeRasterizerState(RasterizerState *state) { #endif } -RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexData &v1) { - uint8_t alpha = v1.color0 >> 24; +static inline void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, bool useColor) { + if (useColor) { + if ((v0.color0 & 0x00FFFFFF) != 0x00FFFFFF) + state->flags |= RasterizerStateFlags::VERTEX_NON_FULL_WHITE; + uint8_t alpha = v0.color0 >> 24; + if (alpha != 0) + state->flags |= RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO; + if (alpha != 0xFF) + state->flags |= RasterizerStateFlags::VERTEX_ALPHA_NON_FULL; + } + if (!(v0.fogdepth >= 1.0f)) + state->flags |= RasterizerStateFlags::VERTEX_HAS_FOG; +} - bool changedPixelID = false; - bool changedSamplerID = false; - if (!state.pixelID.clearMode) { - auto &pixelID = state.pixelID; +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0) { + CalculateRasterStateFlags(state, v0, true); +} + +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, bool forceFlat) { + CalculateRasterStateFlags(state, v0, !forceFlat && state->shadeGouraud); + CalculateRasterStateFlags(state, v1, true); +} + +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, const VertexData &v2) { + CalculateRasterStateFlags(state, v0, state->shadeGouraud); + CalculateRasterStateFlags(state, v1, state->shadeGouraud); + CalculateRasterStateFlags(state, v2, true); +} + +static inline int OptimizePixelIDFlags(const RasterizerStateFlags &flags) { + return (int)flags & (int)RasterizerStateFlags::OPTIMIZED_PIXELID; +} + +static inline int OptimizeSamplerIDFlags(const RasterizerStateFlags &flags) { + return (int)flags & (int)RasterizerStateFlags::OPTIMIZED_SAMPLERID; +} + +static inline int OptimizeAllFlags(const RasterizerStateFlags &flags) { + return OptimizePixelIDFlags(flags) | OptimizeSamplerIDFlags(flags); +} + +static inline RasterizerStateFlags ClearFlags(const RasterizerStateFlags &flags, const RasterizerStateFlags &mask) { + int clearBits = (int)flags & (int)mask; + return (RasterizerStateFlags)((int)flags & ~clearBits); +} + +static inline RasterizerStateFlags ReplacePixelIDFlags(const RasterizerStateFlags &flags, const RasterizerStateFlags &replace) { + RasterizerStateFlags updated = ClearFlags(flags, RasterizerStateFlags::OPTIMIZED_PIXELID); + return updated | (RasterizerStateFlags)OptimizePixelIDFlags(replace); +} + +static inline RasterizerStateFlags ReplaceSamplerIDFlags(const RasterizerStateFlags &flags, const RasterizerStateFlags &replace) { + RasterizerStateFlags updated = ClearFlags(flags, RasterizerStateFlags::OPTIMIZED_SAMPLERID); + return updated | (RasterizerStateFlags)OptimizeSamplerIDFlags(replace); +} + +static bool CheckClutAlphaFull(RasterizerState *state) { + // We only need to check it once. + if (state->flags & RasterizerStateFlags::CLUT_ALPHA_CHECKED) + return !(state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_FULL); + // For now, let's keep things simple. + const SamplerID &samplerID = state->samplerID; + if (samplerID.hasClutOffset || !samplerID.useSharedClut) + return false; + + uint32_t count = samplerID.TexFmt() == GE_TFMT_CLUT4 ? 16 : 256; + if (samplerID.hasClutMask) + count = std::min(count, ((samplerID.cached.clutFormat >> 8) & 0xFF) + 1); + + u32 alphaSum = 0xFFFFFFFF; + if (samplerID.ClutFmt() == GE_CMODE_32BIT_ABGR8888) { + CheckMask32((const uint32_t *)samplerID.cached.clut, count, &alphaSum); + } else { + CheckMask16((const uint16_t *)samplerID.cached.clut, count, &alphaSum); + } + + bool onlyFull = true; + switch (samplerID.ClutFmt()) { + case GE_CMODE_16BIT_BGR5650: + break; + + case GE_CMODE_16BIT_ABGR5551: + onlyFull = (alphaSum & 0x8000) != 0; + break; + + case GE_CMODE_16BIT_ABGR4444: + onlyFull = (alphaSum & 0xF000) == 0xF000; + break; + + case GE_CMODE_32BIT_ABGR8888: + onlyFull = (alphaSum & 0xFF000000) == 0xFF000000; + break; + } + + // Might just be different patterns, but if alphaSum != 0, it can't contain zero. + if (alphaSum != 0) + state->flags |= RasterizerStateFlags::CLUT_ALPHA_NON_ZERO; + if (!onlyFull) + state->flags |= RasterizerStateFlags::CLUT_ALPHA_NON_FULL; + state->flags |= RasterizerStateFlags::CLUT_ALPHA_CHECKED; + + return onlyFull; +} + +static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) { + // Note: all optimizations must be undoable. + RasterizerStateFlags optimize = RasterizerStateFlags::NONE; + auto &pixelID = state->pixelID; + auto &samplerID = state->samplerID; + + bool alphaZero = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_ZERO); + bool alphaFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + bool needTextureAlpha = state->enableTextures && samplerID.useTextureAlpha; + + if (!pixelID.clearMode) { auto &cached = pixelID.cached; - bool useTextureAlpha = state.enableTextures && state.samplerID.useTextureAlpha; - if (pixelID.alphaBlend && pixelID.AlphaBlendSrc() == PixelBlendFactor::SRCALPHA && !useTextureAlpha) { + bool alphaBlend = pixelID.alphaBlend || (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF); + if (needTextureAlpha && alphaBlend && alphaFull) { + bool usesClut = (samplerID.texfmt & 4) != 0; + if (usesClut && CheckClutAlphaFull(state)) + needTextureAlpha = false; + } + + if (alphaBlend && !needTextureAlpha) { + PixelBlendFactor src = pixelID.AlphaBlendSrc(); + PixelBlendFactor dst = pixelID.AlphaBlendDst(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + src = PixelBlendFactor::SRCALPHA; + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + dst = PixelBlendFactor::INVSRCALPHA; + // Okay, we may be able to convert this to a fixed value. - if (alpha == 0) { - pixelID.alphaBlendSrc = (uint8_t)PixelBlendFactor::ZERO; - changedPixelID = true; - } else if (alpha == 0xFF) { - pixelID.alphaBlendSrc = (uint8_t)PixelBlendFactor::ONE; - changedPixelID = true; + if (alphaZero || alphaFull) { + // If it was already set and we still can, set it again. + if (src == PixelBlendFactor::SRCALPHA) + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_SRC; + if (dst == PixelBlendFactor::INVSRCALPHA) + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_DST; + } + if (alphaFull && (src == PixelBlendFactor::SRCALPHA || src == PixelBlendFactor::ONE) && (dst == PixelBlendFactor::INVSRCALPHA || dst == PixelBlendFactor::ZERO)) { + optimize |= RasterizerStateFlags::OPTIMIZED_BLEND_OFF; } } - if (pixelID.alphaBlend && pixelID.AlphaBlendDst() == PixelBlendFactor::INVSRCALPHA && !useTextureAlpha) { - if (alpha == 0) { - pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::ONE; - changedPixelID = true; - } else if (alpha == 0xFF) { - pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::ZERO; - changedPixelID = true; + + if (alphaBlend && (needTextureAlpha || !alphaFull)) { + // Okay, we're blending, and we need to. Are we alpha testing? + GEComparison alphaTestFunc = pixelID.AlphaTestFunc(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE) + alphaTestFunc = GE_COMP_NOTEQUAL; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) + alphaTestFunc = GE_COMP_GREATER; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) + alphaTestFunc = GE_COMP_ALWAYS; + + PixelBlendFactor src = pixelID.AlphaBlendSrc(); + PixelBlendFactor dst = pixelID.AlphaBlendDst(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + src = PixelBlendFactor::SRCALPHA; + if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + dst = PixelBlendFactor::INVSRCALPHA; + + if (alphaTestFunc == GE_COMP_ALWAYS && src == PixelBlendFactor::SRCALPHA && dst == PixelBlendFactor::INVSRCALPHA) { + bool usesClut = (samplerID.texfmt & 4) != 0; + bool couldHaveZeroTexAlpha = true; + if (usesClut && CheckClutAlphaFull(state)) + couldHaveZeroTexAlpha = false; + if (state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_ZERO) + couldHaveZeroTexAlpha = false; + + // Blending is expensive, since we read the target. Force alpha testing on. + if (!pixelID.depthWrite && !pixelID.stencilTest && couldHaveZeroTexAlpha) + optimize |= RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON; } } - if (pixelID.alphaBlend && pixelID.AlphaBlendSrc() == PixelBlendFactor::ONE && pixelID.AlphaBlendDst() == PixelBlendFactor::ZERO) { - if (pixelID.AlphaBlendEq() == GE_BLENDMODE_MUL_AND_ADD) { - pixelID.alphaBlend = false; - changedPixelID = true; - } + + bool applyFog = pixelID.applyFog || (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF); + if (applyFog) { + bool hasFog = state->flags & RasterizerStateFlags::VERTEX_HAS_FOG; + if (!hasFog) + optimize |= RasterizerStateFlags::OPTIMIZED_FOG_OFF; } } - if (state.enableTextures) { - if (v1.color0 == 0xFFFFFFFF) { + + if (state->enableTextures) { + bool colorFull = !(state->flags & RasterizerStateFlags::VERTEX_NON_FULL_WHITE); + if (colorFull && (!needTextureAlpha || alphaFull)) { // Modulate is common, sometimes even with a fixed color. Replace is cheaper. - if (state.samplerID.TexFunc() == GE_TEXFUNC_MODULATE) { - state.samplerID.texFunc = (uint8_t)GE_TEXFUNC_REPLACE; - changedSamplerID = true; + GETexFunc texFunc = samplerID.TexFunc(); + if (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) + texFunc = GE_TEXFUNC_MODULATE; + + if (texFunc == GE_TEXFUNC_MODULATE) + optimize |= RasterizerStateFlags::OPTIMIZED_TEXREPLACE; + } + + bool usesClut = (samplerID.texfmt & 4) != 0; + if (usesClut && alphaFull && samplerID.useTextureAlpha) { + GEComparison alphaTestFunc = pixelID.AlphaTestFunc(); + // We optimize > 0 to != 0, so this is especially common. + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE) + alphaTestFunc = GE_COMP_NOTEQUAL; + // > 16, 8, or similar are also very common. + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) + alphaTestFunc = GE_COMP_GREATER; + if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) + alphaTestFunc = GE_COMP_ALWAYS; + + bool alphaTest = (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) && pixelID.alphaTestRef < 0xFF && !state->pixelID.hasAlphaTestMask; + if (alphaTest) { + bool canSkipAlphaTest = CheckClutAlphaFull(state); + if ((state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_ZERO) && pixelID.alphaTestRef == 0) + canSkipAlphaTest = true; + if (canSkipAlphaTest) + optimize |= alphaTestFunc == GE_COMP_NOTEQUAL ? RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE : RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT; } } } - if (changedPixelID) - state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID); - if (changedSamplerID) { - state.linear = Sampler::GetLinearFunc(state.samplerID); - state.nearest = Sampler::GetNearestFunc(state.samplerID); + return optimize; +} - // Since the definitions are the same, just force this setting using the func pointer. - if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) - state.nearest = state.linear; - else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) - state.linear = state.nearest; +static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStateFlags &optimize) { + bool changed = false; + + // Check if we can compile the new funcs before replacing. + if (OptimizePixelIDFlags(state->flags) != OptimizePixelIDFlags(optimize)) { + bool canFull = !(state->flags & RasterizerStateFlags::VERTEX_ALPHA_NON_FULL); + + PixelFuncID pixelID = state->pixelID; + if (optimize & RasterizerStateFlags::OPTIMIZED_BLEND_OFF) + pixelID.alphaBlend = false; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_OFF) + pixelID.alphaBlend = true; + if (optimize & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + pixelID.alphaBlendSrc = (uint8_t)(canFull ? PixelBlendFactor::ONE : PixelBlendFactor::ZERO); + else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC) + pixelID.alphaBlendSrc = (uint8_t)PixelBlendFactor::SRCALPHA; + if (optimize & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + pixelID.alphaBlendDst = (uint8_t)(canFull ? PixelBlendFactor::ZERO : PixelBlendFactor::ONE); + else if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST) + pixelID.alphaBlendDst = (uint8_t)PixelBlendFactor::INVSRCALPHA; + if (optimize & RasterizerStateFlags::OPTIMIZED_FOG_OFF) + pixelID.applyFog = false; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF) + pixelID.applyFog = true; + if (optimize & (RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT)) + pixelID.alphaTestFunc = GE_COMP_ALWAYS; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE) + pixelID.alphaTestFunc = GE_COMP_NOTEQUAL; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT) + pixelID.alphaTestFunc = GE_COMP_GREATER; + else if (optimize & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) { + pixelID.alphaTestFunc = GE_COMP_NOTEQUAL; + pixelID.alphaTestRef = 0; + pixelID.hasAlphaTestMask = false; + } else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) { + pixelID.alphaTestFunc = GE_COMP_ALWAYS; + } + + SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr); + // Can't compile during runtime. This failing is a bit of a problem when undoing... + if (drawPixel) { + state->drawPixel = drawPixel; + memcpy(&state->pixelID, &pixelID, sizeof(PixelFuncID)); + state->flags = ReplacePixelIDFlags(state->flags, optimize) | RasterizerStateFlags::OPTIMIZED; + changed = true; + } } - return state; + if (OptimizeSamplerIDFlags(state->flags) != OptimizeSamplerIDFlags(optimize)) { + SamplerID samplerID = state->samplerID; + if (optimize & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) + samplerID.texFunc = (uint8_t)GE_TEXFUNC_REPLACE; + else if (state->flags & RasterizerStateFlags::OPTIMIZED_TEXREPLACE) + samplerID.texFunc = (uint8_t)GE_TEXFUNC_MODULATE; + + Sampler::LinearFunc linear = Sampler::GetLinearFunc(samplerID, nullptr); + Sampler::LinearFunc nearest = Sampler::GetNearestFunc(samplerID, nullptr); + // Can't compile during runtime. This failing is a bit of a problem when undoing... + if (linear && nearest) { + // Since the definitions are the same, just force this setting using the func pointer. + if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { + state->nearest = linear; + state->linear = linear; + } else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) { + state->nearest = nearest; + state->linear = nearest; + } else { + state->nearest = nearest; + state->linear = linear; + } + memcpy(&state->samplerID, &samplerID, sizeof(SamplerID)); + state->flags = ReplaceSamplerIDFlags(state->flags, optimize) | RasterizerStateFlags::OPTIMIZED; + changed = true; + } + } + + state->lastFlags = state->flags; + return changed; +} + +bool OptimizeRasterState(RasterizerState *state) { + if (state->flags == state->lastFlags) + return false; + + RasterizerStateFlags optimize = DetectStateOptimizations(state); + + // If it was optimized before, just revert and don't churn. + if ((state->flags & RasterizerStateFlags::OPTIMIZED) && OptimizeAllFlags(state->flags) != OptimizeAllFlags(optimize)) { + optimize = RasterizerStateFlags::NONE; + } else if (optimize == RasterizerStateFlags::NONE && !(state->flags & RasterizerStateFlags::OPTIMIZED)) { + state->lastFlags = state->flags; + return false; + } + + return ApplyStateOptimizations(state, optimize); +} + +RasterizerState OptimizeFlatRasterizerState(const RasterizerState &origState, const VertexData &v1) { + uint8_t alpha = v1.color0 >> 24; + RasterizerState state = origState; + + // Sometimes, a particular draw can do better than the overall state. + state.flags = ClearFlags(state.flags, RasterizerStateFlags::VERTEX_FLAT_RESET); + CalculateRasterStateFlags(&state, v1, true); + + RasterizerStateFlags optimize = DetectStateOptimizations(&state); + if (OptimizeAllFlags(state.flags) != OptimizeAllFlags(optimize)) { + ApplyStateOptimizations(&state, optimize); + return state; + } + + return origState; } static inline u8 ClampFogDepth(float fogdepth) { @@ -303,18 +582,18 @@ static inline bool IsRightSideOrFlatBottomLine(const Vec2& vertex, const Ve } } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { const u8 **tptr0 = const_cast(&state.texptr[texlevel]); const uint16_t *bufw0 = &state.texbufw[texlevel]; if (!bilinear) { - return state.nearest(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); + return state.nearest(s, t, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); } - return state.linear(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); + return state.linear(s, t, prim_color, tptr0, bufw0, texlevel, frac_texlevel, state.samplerID); } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { - return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texlevel, frac_texlevel, bilinear, state); +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { + return ApplyTexturing(s, t, prim_color, texlevel, frac_texlevel, bilinear, state); } // Produces a signed 1.27.4 value. @@ -332,7 +611,7 @@ static int TexLog2(float delta) { return useful - 127 * 16; } -static inline void CalculateSamplingParams(const float ds, const float dt, const RasterizerState &state, int &level, int &levelFrac, bool &filt) { +static inline void CalculateSamplingParams(const float ds, const float dt, float w, const RasterizerState &state, int &level, int &levelFrac, bool &filt) { const int width = 1 << state.samplerID.width0Shift; const int height = 1 << state.samplerID.height0Shift; @@ -340,11 +619,11 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const int detail; switch (state.TexLevelMode()) { case GE_TEXLEVEL_MODE_AUTO: - detail = TexLog2(std::max(ds * width, dt * height)); + detail = TexLog2(std::max(std::abs(ds * width), std::abs(dt * height))); break; case GE_TEXLEVEL_MODE_SLOPE: // This is always offset by an extra texlevel. - detail = 1 * 16 + TexLog2(state.textureLodSlope); + detail = TexLog2(2.0f * w * state.textureLodSlope); break; case GE_TEXLEVEL_MODE_CONST: default: @@ -377,19 +656,19 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const filt = state.magFilt; } -static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int x, int y) { +static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, float w) { float ds = s[1] - s[0]; float dt = t[2] - t[0]; int level; int levelFrac; bool bilinear; - CalculateSamplingParams(ds, dt, state, level, levelFrac, bilinear); + CalculateSamplingParams(ds, dt, w, state, level, levelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); for (int i = 0; i < 4; ++i) { if (mask[i] >= 0) - prim_color[i] = ApplyTexturing(s[i], t[i], ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, ToVec4IntArg(prim_color[i]), level, levelFrac, bilinear, state); + prim_color[i] = ApplyTexturing(s[i], t[i], ToVec4IntArg(prim_color[i]), level, levelFrac, bilinear, state); } } @@ -589,7 +868,7 @@ void DrawTriangleSlice( // All the z values are the same, no interpolation required. // This is common, and when we interpolate, we lose accuracy. const bool flatZ = v0.screenpos.z == v1.screenpos.z && v0.screenpos.z == v2.screenpos.z; - const bool flatColorAll = clearMode || !state.shadeGouraud; + const bool flatColorAll = !state.shadeGouraud; const bool flatColor0 = flatColorAll || (v0.color0 == v1.color0 && v0.color0 == v2.color0); const bool flatColor1 = flatColorAll || (v0.color1 == v1.color1 && v0.color1 == v2.color1); const bool noFog = clearMode || !pixelID.applyFog || (v0.fogdepth >= 1.0f && v1.fogdepth >= 1.0f && v2.fogdepth >= 1.0f); @@ -717,7 +996,13 @@ void DrawTriangleSlice( GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t); } - ApplyTexturing(state, prim_color, mask, s, t, curX, curY); + if (state.TexLevelMode() == GE_TEXLEVEL_MODE_SLOPE) { + // Not sure what's right, but we need one value for the slope. + float clipw = (v0.clipw * w0.x + v1.clipw * w1.x + v2.clipw * w2.x) * wsum_recip.x; + ApplyTexturing(state, prim_color, mask, s, t, clipw); + } else { + ApplyTexturing(state, prim_color, mask, s, t, 0.0f); + } } if (!clearMode) { @@ -796,11 +1081,18 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & int entireY1 = std::min(v0.screenpos.y, v1.screenpos.y); int entireX2 = std::max(v0.screenpos.x, v1.screenpos.x) - 1; int entireY2 = std::max(v0.screenpos.y, v1.screenpos.y) - 1; - int minX = std::max(entireX1, range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); - int minY = std::max(entireY1, range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minX = std::max(entireX1 & ~(SCREEN_SCALE_FACTOR - 1), range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minY = std::max(entireY1 & ~(SCREEN_SCALE_FACTOR - 1), range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); int maxX = std::min(entireX2, range.x2); int maxY = std::min(entireY2, range.y2); + // If TL x or y was after the half, we don't draw the pixel. + // TODO: Verify what center is used, allowing slight offset makes gpu/primitives/trianglefan pass. + if (minX < entireX1 - 1) + minX += SCREEN_SCALE_FACTOR; + if (minY < entireY1 - 1) + minY += SCREEN_SCALE_FACTOR; + RasterizerState state = OptimizeFlatRasterizerState(rastState, v1); Vec2f rowST(0.0f, 0.0f); @@ -819,8 +1111,8 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & tc1.t() *= 1.0f / (float)(1 << state.samplerID.height0Shift); } - int diffX = (entireX2 - entireX1 + 1) / SCREEN_SCALE_FACTOR; - int diffY = (entireY2 - entireY1 + 1) / SCREEN_SCALE_FACTOR; + float diffX = (entireX2 - entireX1 + 1) / (float)SCREEN_SCALE_FACTOR; + float diffY = (entireY2 - entireY1 + 1) / (float)SCREEN_SCALE_FACTOR; float diffS = tc1.s() - tc0.s(); float diffT = tc1.t() - tc0.t(); @@ -853,8 +1145,8 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & } // Okay, now move ST to the minX, minY position. - rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1); - rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1); + rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1 + 1); + rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1 + 1); } // And now what we add to spread out to 4 values. @@ -879,15 +1171,15 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & std::string ztag = StringFromFormat("DisplayListRZ_%08x", state.listPC); #endif - for (int64_t curY = minY; curY <= maxY; curY += SCREEN_SCALE_FACTOR * 2, rowST += sty) { - DrawingCoords p = TransformUnit::ScreenToDrawing(range.x1, curY); + for (int64_t curY = minY; curY < maxY; curY += SCREEN_SCALE_FACTOR * 2, rowST += sty) { + DrawingCoords p = TransformUnit::ScreenToDrawing(minX, curY); int scissorY2 = curY + SCREEN_SCALE_FACTOR > maxY ? -1 : 0; Vec4 scissor_mask = Vec4(0, maxX - minX - SCREEN_SCALE_FACTOR, scissorY2, (maxX - minX - SCREEN_SCALE_FACTOR) | scissorY2); Vec4 scissor_step = Vec4(0, -(SCREEN_SCALE_FACTOR * 2), 0, -(SCREEN_SCALE_FACTOR * 2)); Vec2f st = rowST; - for (int64_t curX = minX; curX <= maxX; curX += SCREEN_SCALE_FACTOR * 2, + for (int64_t curX = minX; curX < maxX; curX += SCREEN_SCALE_FACTOR * 2, st += stx, scissor_mask += scissor_step, p.x = (p.x + 2) & 0x3FF) { @@ -916,7 +1208,7 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords & s = Vec4::AssignToAll(st.s()) + sto4; t = Vec4::AssignToAll(st.t()) + tto4; - ApplyTexturing(state, prim_color, mask, s, t, curX, curY); + ApplyTexturing(state, prim_color, mask, s, t, v1.clipw); } if (!state.pixelID.clearMode) { @@ -1007,9 +1299,9 @@ void DrawPoint(const VertexData &v0, const BinCoords &range, const RasterizerSta int texLevel; int texLevelFrac; bool bilinear; - CalculateSamplingParams(0.0f, 0.0f, state, texLevel, texLevelFrac, bilinear); + CalculateSamplingParams(0.0f, 0.0f, v0.clipw, state, texLevel, texLevelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, bilinear, state); + prim_color = ApplyTexturingSingle(s, t, ToVec4IntArg(prim_color), texLevel, texLevelFrac, bilinear, state); } if (!pixelID.clearMode) @@ -1043,12 +1335,20 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const BinCoords int entireY1 = std::min(v0.screenpos.y, v1.screenpos.y); int entireX2 = std::max(v0.screenpos.x, v1.screenpos.x) - 1; int entireY2 = std::max(v0.screenpos.y, v1.screenpos.y) - 1; - int minX = std::max(entireX1, range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); - int minY = std::max(entireY1, range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minX = std::max(entireX1 & ~(SCREEN_SCALE_FACTOR - 1), range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1); + int minY = std::max(entireY1 & ~(SCREEN_SCALE_FACTOR - 1), range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1); int maxX = std::min(entireX2, range.x2); int maxY = std::min(entireY2, range.y2); + + // If TL x or y was after the half, we don't draw the pixel. + if (minX < entireX1 - 1) + minX += SCREEN_SCALE_FACTOR; + if (minY < entireY1 - 1) + minY += SCREEN_SCALE_FACTOR; + const DrawingCoords pprime = TransformUnit::ScreenToDrawing(minX, minY); - const DrawingCoords pend = TransformUnit::ScreenToDrawing(maxX, maxY); + // Only include the end pixel when it's >= 0.5. + const DrawingCoords pend = TransformUnit::ScreenToDrawing(maxX - SCREEN_SCALE_FACTOR / 2, maxY - SCREEN_SCALE_FACTOR / 2); auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; @@ -1225,7 +1525,7 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const BinCoords void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state) { // TODO: Use a proper line drawing algorithm that handles fractional endpoints correctly. Vec3 a(v0.screenpos.x, v0.screenpos.y, v0.screenpos.z); - Vec3 b(v1.screenpos.x, v1.screenpos.y, v0.screenpos.z); + Vec3 b(v1.screenpos.x, v1.screenpos.y, v1.screenpos.z); int dx = b.x - a.x; int dy = b.y - a.y; @@ -1328,11 +1628,12 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range // If inc is 0, force the delta to zero. float ds = xinc == 0.0 ? 0.0f : (s1 - s) * (float)SCREEN_SCALE_FACTOR * (1.0f / xinc); float dt = yinc == 0.0 ? 0.0f : (t1 - t) * (float)SCREEN_SCALE_FACTOR * (1.0f / yinc); + float w = (v0.clipw * (float)(steps - i) + v1.clipw * (float)i) / steps1; int texLevel; int texLevelFrac; bool texBilinear; - CalculateSamplingParams(ds, dt, state, texLevel, texLevelFrac, texBilinear); + CalculateSamplingParams(ds, dt, w, state, texLevel, texLevelFrac, texBilinear); if (state.antialiasLines) { // TODO: This is a naive and wrong implementation. @@ -1344,7 +1645,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range } PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, texBilinear, state); + prim_color = ApplyTexturingSingle(s, t, ToVec4IntArg(prim_color), texLevel, texLevelFrac, texBilinear, state); } if (!pixelID.clearMode) @@ -1396,7 +1697,14 @@ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) ComputeSamplerID(&id); id.cached.clut = clut; - Sampler::FetchFunc sampler = Sampler::GetFetchFunc(id); + // Slight annoyance, we may have to force a compile. + Sampler::FetchFunc sampler = Sampler::GetFetchFunc(id, nullptr); + if (!sampler) { + Sampler::FlushJit(); + sampler = Sampler::GetFetchFunc(id, nullptr); + if (!sampler) + return false; + } u8 *texptr = Memory::GetPointerWrite(texaddr); u32 *row = (u32 *)buffer.GetData(); diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index bd0b820283..d4e4ebe17c 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -17,6 +17,7 @@ #pragma once +#include #include "GPU/Software/DrawPixel.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/Sampler.h" @@ -29,9 +30,41 @@ struct GPUDebugBuffer; struct BinCoords; +class BinManager; namespace Rasterizer { +enum class RasterizerStateFlags { + NONE = 0, + VERTEX_NON_FULL_WHITE = 0x0001, + VERTEX_ALPHA_NON_ZERO = 0x0002, + VERTEX_ALPHA_NON_FULL = 0x0004, + VERTEX_HAS_FOG = 0x0008, + + CLUT_ALPHA_CHECKED = 0x0010, + CLUT_ALPHA_NON_FULL = 0x0020, + CLUT_ALPHA_NON_ZERO = 0x0040, + + VERTEX_FLAT_RESET = VERTEX_NON_FULL_WHITE | VERTEX_ALPHA_NON_FULL | VERTEX_ALPHA_NON_ZERO | VERTEX_HAS_FOG, + + OPTIMIZED = 0x0001'0000, + OPTIMIZED_BLEND_SRC = 0x0002'0000, + OPTIMIZED_BLEND_DST = 0x0004'0000, + OPTIMIZED_BLEND_OFF = 0x0008'0000, + OPTIMIZED_TEXREPLACE = 0x0010'0000, + OPTIMIZED_FOG_OFF = 0x0020'0000, + OPTIMIZED_ALPHATEST_OFF_NE = 0x0040'0000, + OPTIMIZED_ALPHATEST_OFF_GT = 0x0080'0000, + OPTIMIZED_ALPHATEST_ON = 0x0100'0000, + + // Anything that changes the actual pixel or sampler func. + OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | OPTIMIZED_ALPHATEST_OFF_NE | OPTIMIZED_ALPHATEST_OFF_GT | OPTIMIZED_ALPHATEST_ON, + OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE, + + INVALID = 0x7FFFFFFF, +}; +ENUM_CLASS_BITOPS(RasterizerStateFlags); + struct RasterizerState { PixelFuncID pixelID; SamplerID samplerID; @@ -42,6 +75,8 @@ struct RasterizerState { uint16_t texbufw[8]{}; const u8 *texptr[8]{}; float textureLodSlope; + RasterizerStateFlags flags = RasterizerStateFlags::NONE; + RasterizerStateFlags lastFlags = RasterizerStateFlags::INVALID; struct { uint8_t maxTexLevel : 3; @@ -66,7 +101,11 @@ struct RasterizerState { } }; -void ComputeRasterizerState(RasterizerState *state); +void ComputeRasterizerState(RasterizerState *state, BinManager *binner); +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0); +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, bool forceFlat); +void CalculateRasterStateFlags(RasterizerState *state, const VertexData &v0, const VertexData &v1, const VertexData &v2); +bool OptimizeRasterState(RasterizerState *state); // Draws a triangle if its vertices are specified in counter-clockwise order void DrawTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const BinCoords &range, const RasterizerState &state); diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 5cc40566d6..d7925a66a1 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -72,17 +72,59 @@ static uint32_t StandardAlphaBlend(uint32_t source, uint32_t dst) { } // Through mode, with the specific Darkstalker settings. -inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { +template +static inline void DrawSinglePixel(u16 *pixel, const u32 color_in) { u32 new_color; // Because of this check, we only support src.a / 1-src.a blending. - if ((color_in >> 24) == 255) { + // We take advantage of short circuiting by checking the constant (template) value first. + if (!alphaBlend || (color_in >> 24) == 255) { new_color = color_in & 0xFFFFFF; } else { - const u32 old_color = RGBA5551ToRGBA8888(*pixel); + u32 old_color; + switch (fmt) { + case GE_FORMAT_565: + old_color = RGB565ToRGBA8888(*pixel); + break; + case GE_FORMAT_5551: + old_color = RGBA5551ToRGBA8888(*pixel); + break; + case GE_FORMAT_4444: + old_color = RGBA4444ToRGBA8888(*pixel); + break; + default: + break; + } + new_color = StandardAlphaBlend(color_in, old_color); } - new_color |= (*pixel & 0x8000) ? 0xff000000 : 0x00000000; - *pixel = RGBA8888ToRGBA5551(new_color); + + switch (fmt) { + case GE_FORMAT_565: + *pixel = RGBA8888ToRGB565(new_color); + break; + case GE_FORMAT_5551: + *pixel = RGBA8888ToRGBA555X(new_color) | (*pixel & 0x8000); + break; + case GE_FORMAT_4444: + *pixel = RGBA8888ToRGBA444X(new_color) | (*pixel & 0xF000); + break; + default: + break; + } +} + +template +static inline void DrawSinglePixel32(u32 *pixel, const u32 color_in) { + u32 new_color; + // Because of this check, we only support src.a / 1-src.a blending. + if ((color_in >> 24) == 255 || !alphaBlend) { + new_color = color_in & 0xFFFFFF; + } else { + const u32 old_color = *pixel; + new_color = StandardAlphaBlend(color_in, old_color); + } + new_color |= *pixel & 0xFF000000; + *pixel = new_color; } // Check if we can safely ignore the alpha test, assuming standard alpha blending. @@ -108,18 +150,18 @@ static inline bool AlphaTestIsNeedless(const PixelFuncID &pixelID) { return false; } -bool UseDrawSinglePixel5551(const PixelFuncID &pixelID) { +static bool UseDrawSinglePixel(const PixelFuncID &pixelID) { if (pixelID.clearMode || pixelID.colorTest || pixelID.stencilTest) return false; if (!AlphaTestIsNeedless(pixelID) || pixelID.DepthTestFunc() != GE_COMP_ALWAYS) return false; - if (pixelID.FBFormat() != GE_FORMAT_5551 || !pixelID.alphaBlend) - return false; // We skip blending when alpha = FF, so we can't allow other blend modes. - if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) - return false; - if (pixelID.AlphaBlendDst() != PixelBlendFactor::INVSRCALPHA) - return false; + if (pixelID.alphaBlend) { + if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) + return false; + if (pixelID.AlphaBlendDst() != PixelBlendFactor::INVSRCALPHA) + return false; + } if (pixelID.dithering || pixelID.applyLogicOp || pixelID.applyColorWriteMask) return false; @@ -156,13 +198,120 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } +template +static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { + const u8 *texptr = state.texptr[0]; + uint16_t texbufw = state.texbufw[0]; + + int t = t_start; + const Vec4 c0 = Vec4::FromRGBA(color0); + for (int y = pos0.y; y < pos1.y; y++) { + int s = s_start; + u16 *pixel16 = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + u32 *pixel32 = fb.Get32Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); + if (isWhite) { + if (!alphaBlend || tex_color.a() != 0) { + u32 tex_color32 = tex_color.ToRGBA(); + if (fmt == GE_FORMAT_8888) + DrawSinglePixel32(pixel32, tex_color32); + else + DrawSinglePixel(pixel16, tex_color32); + } + } else { + Vec4 prim_color = c0; + prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); + if (!alphaBlend || prim_color.a() > 0) { + if (fmt == GE_FORMAT_8888) + DrawSinglePixel32(pixel32, prim_color.ToRGBA()); + else + DrawSinglePixel(pixel16, prim_color.ToRGBA()); + } + } + s += ds; + if (fmt == GE_FORMAT_8888) + pixel32++; + else + pixel16++; + } + t += dt; + } +} + +template +static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { + switch (state.pixelID.FBFormat()) { + case GE_FORMAT_565: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + case GE_FORMAT_5551: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + case GE_FORMAT_4444: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + case GE_FORMAT_8888: + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + break; + default: + // Invalid, don't draw anything... + break; + } +} + +template +static void DrawSpriteNoTex(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { + if (alphaBlend && Vec4::FromRGBA(color0).a() == 0) + return; + + for (int y = pos0.y; y < pos1.y; y++) { + if (fmt == GE_FORMAT_8888) { + u32 *pixel = fb.Get32Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + DrawSinglePixel32(pixel, color0); + pixel++; + } + } else { + u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + DrawSinglePixel(pixel, color0); + pixel++; + } + } + } +} + +template +static void DrawSpriteNoTex(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { + switch (state.pixelID.FBFormat()) { + case GE_FORMAT_565: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + case GE_FORMAT_5551: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + case GE_FORMAT_4444: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + case GE_FORMAT_8888: + DrawSpriteNoTex(pos0, pos1, color0, state); + break; + default: + // Invalid, don't draw anything... + break; + } +} + void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state) { const u8 *texptr = state.texptr[0]; GETextureFormat texfmt = state.samplerID.TexFmt(); uint16_t texbufw = state.texbufw[0]; - Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID); + // We won't flush, since we compile all samplers together. + Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID, nullptr); + _dbg_assert_msg_(fetchFunc != nullptr, "Failed to get precompiled fetch func"); auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; @@ -209,45 +358,19 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran pos0.y = scissorTL.y; } - if (UseDrawSinglePixel5551(pixelID) && samplerID.TexFunc() == GE_TEXFUNC_MODULATE && samplerID.useTextureAlpha) { - if (isWhite) { - int t = t_start; - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - u32 tex_color = Vec4(fetchFunc(s, t, texptr, texbufw, 0, state.samplerID)).ToRGBA(); - if (tex_color & 0xFF000000) { - DrawSinglePixel5551(pixel, tex_color); - } - s += ds; - pixel++; - } - t += dt; - } + if (UseDrawSinglePixel(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { + if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { + if (pixelID.alphaBlend) + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + else + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { - int t = t_start; - const Vec4 c0 = Vec4::FromRGBA(v1.color0); - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - Vec4 prim_color = c0; - Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); - prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); - if (prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color.ToRGBA()); - } - s += ds; - pixel++; - } - t += dt; - } + if (pixelID.alphaBlend) + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + else + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { - int xoff = ((v0.screenpos.x & 15) + 1) / 2; - int yoff = ((v0.screenpos.y & 15) + 1) / 2; - float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); float dtf = dt * (1.0f / (float)(1 << state.samplerID.height0Shift)); float sf_start = s_start * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -261,7 +384,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran // Not really that fast but faster than triangle. for (int x = pos0.x; x < pos1.x; x++) { if (CheckDepthTestPassed(pixelID.DepthTestFunc(), x, y, pixelID.cached.depthbufStride, z)) { - Vec4 prim_color = state.nearest(s, t, xoff, yoff, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); + Vec4 prim_color = state.nearest(s, t, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); state.drawPixel(x, y, z, fog, ToVec4IntArg(prim_color), pixelID); } @@ -274,7 +397,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran float s = sf_start; // Not really that fast but faster than triangle. for (int x = pos0.x; x < pos1.x; x++) { - Vec4 prim_color = state.nearest(s, t, xoff, yoff, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); + Vec4 prim_color = state.nearest(s, t, ToVec4IntArg(c0), &texptr, &texbufw, 0, 0, state.samplerID); state.drawPixel(x, y, z, fog, ToVec4IntArg(prim_color), pixelID); s += dsf; } @@ -287,17 +410,11 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (pos1.y > scissorBR.y) pos1.y = scissorBR.y + 1; if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; - if (UseDrawSinglePixel5551(pixelID)) { - if (Vec4::FromRGBA(v1.color0).a() == 0) - return; - - for (int y = pos0.y; y < pos1.y; y++) { - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - DrawSinglePixel5551(pixel, v1.color0); - pixel++; - } - } + if (UseDrawSinglePixel(pixelID)) { + if (pixelID.alphaBlend) + DrawSpriteNoTex(pos0, pos1, v1.color0, state); + else + DrawSpriteNoTex(pos0, pos1, v1.color0, state); } else if (pixelID.earlyZChecks) { const Vec4 prim_color = Vec4::FromRGBA(v1.color0); for (int y = pos0.y; y < pos1.y; y++) { @@ -320,12 +437,14 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran #if defined(SOFTGPU_MEMORY_TAGGING_BASIC) || defined(SOFTGPU_MEMORY_TAGGING_DETAILED) uint32_t bpp = pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2; - std::string tag = StringFromFormat("DisplayListR_%08x", state.listPC); - std::string ztag = StringFromFormat("DisplayListRZ_%08x", state.listPC); + char tag[64]{}; + // char ztag[64]{}; + int tagLen = snprintf(tag, sizeof(tag), "DisplayListR_%08x", state.listPC); + // int ztagLen = snprintf(ztag, sizeof(ztag), "DisplayListRZ_%08x", state.listPC); for (int y = pos0.y; y < pos1.y; y++) { uint32_t row = gstate.getFrameBufAddress() + y * pixelID.cached.framebufStride * bpp; - NotifyMemInfo(MemBlockFlags::WRITE, row + pos0.x * bpp, (pos1.x - pos0.x) * bpp, tag.c_str(), tag.size()); + NotifyMemInfo(MemBlockFlags::WRITE, row + pos0.x * bpp, (pos1.x - pos0.x) * bpp, tag, tagLen); } #endif } @@ -345,24 +464,6 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b const RasterizerState &state = binner.State(); g_DarkStalkerStretch = DSStretch::Off; - // Check for 1:1 texture mapping. In that case we can call DrawSprite. - int xdiff = v1.screenpos.x - v0.screenpos.x; - int ydiff = v1.screenpos.y - v0.screenpos.y; - int udiff = (v1.texturecoords.x - v0.texturecoords.x) * (float)SCREEN_SCALE_FACTOR; - int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * (float)SCREEN_SCALE_FACTOR; - bool coord_check = - (xdiff == udiff || xdiff == -udiff) && - (ydiff == vdiff || ydiff == -vdiff); - // Currently only works for TL/BR, which is the most common but not required. - bool orient_check = xdiff >= 0 && ydiff >= 0; - // We already have a fast path for clear in ClearRectangle. - bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); - // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. - bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; - if ((coord_check || !state.enableTextures) && orient_check && state_check && subpixel_check) { - binner.AddSprite(v0, v1); - return true; - } // Eliminate the stretch blit in DarkStalkers. // We compensate for that when blitting the framebuffer in SoftGpu.cpp. @@ -390,9 +491,44 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b g_needsClearAfterDialog = true; } } + + // Check for 1:1 texture mapping. In that case we can call DrawSprite. + int xdiff = v1.screenpos.x - v0.screenpos.x; + int ydiff = v1.screenpos.y - v0.screenpos.y; + int udiff = (v1.texturecoords.x - v0.texturecoords.x) * (float)SCREEN_SCALE_FACTOR; + int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * (float)SCREEN_SCALE_FACTOR; + + // Currently only works for TL/BR, which is the most common but not required. + bool orient_check = xdiff >= 0 && ydiff >= 0; + // We already have a fast path for clear in ClearRectangle. + bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && !state.textureProj; + bool coord_check = true; + if (state.enableTextures) { + state_check = state_check && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); + coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); + } + // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. + bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; + if (coord_check && orient_check && state_check && subpixel_check) { + binner.AddSprite(v0, v1); + return true; + } return false; } +static bool IsCoordRectangleCompatible(const RasterizerState &state, const ClipVertexData &data) { + if (!state.throughMode) { + // See AreCoordsRectangleCompatible() for most of these, this just checks the main vert. + if (data.OutsideRange()) + return false; + if (data.clippos.w < 0.0f) + return false; + if (data.clippos.z < -data.clippos.w) + return false; + } + return true; +} + static bool AreCoordsRectangleCompatible(const RasterizerState &state, const ClipVertexData &data0, const ClipVertexData &data1) { if (data1.v.color0 != data0.v.color0) return false; @@ -405,7 +541,7 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli if (data1.v.color1 != data0.v.color1) return false; // This means it should be culled, outside range. - if (data1.OutsideRange() || data0.OutsideRange()) + if (data1.OutsideRange()) return false; // Do we have to think about perspective correction or slope mip level? if (state.enableTextures && data1.clippos.w != data0.clippos.w) { @@ -414,6 +550,12 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli if (data1.clippos.w - halftexel > data0.clippos.w || data1.clippos.w + halftexel < data0.clippos.w) return false; } + // We might need to cull this if all verts have negative w, which doesn't seem to happen for rectangles. + if (data1.clippos.w < 0.0f) + return false; + // And we also may need to clip, even if flat. + if (data1.clippos.z < -data1.clippos.w) + return false; // If we're projecting textures, only allow an exact match for simplicity. if (state.enableTextures && data1.v.texturecoords.q() != data0.v.texturecoords.q()) return false; @@ -428,10 +570,13 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Cli } bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex) { + if (!IsCoordRectangleCompatible(state, data[0])) + return false; + // Color and Z must be flat. Also find the TL and BR meanwhile. int tl = 0, br = 0; for (int i = 1; i < 4; ++i) { - if (!AreCoordsRectangleCompatible(state, data[i], data[0])) + if (!AreCoordsRectangleCompatible(state, data[0], data[i])) return false; if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) @@ -483,40 +628,54 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData return false; } -bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex) { +bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex) { + if (!IsCoordRectangleCompatible(state, data[0])) + return false; + // Color and Z must be flat. - for (int i = 1; i < c; ++i) { - if (!AreCoordsRectangleCompatible(state, data[i], data[0])) + int tl = 0, br = 0; + for (int i = 1; i < 4; ++i) { + if (!AreCoordsRectangleCompatible(state, data[0], data[i])) return false; + + if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) + tl = i; + if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y >= data[br].v.screenpos.y) + br = i; } - // Check for the common case: a single TL-TR-BR-BL. - if (c == 4) { - const auto &pos0 = data[0].v.screenpos, &pos1 = data[1].v.screenpos; - const auto &pos2 = data[2].v.screenpos, &pos3 = data[3].v.screenpos; - if (pos0.x == pos3.x && pos1.x == pos2.x && pos0.y == pos1.y && pos3.y == pos2.y) { - // Looking like yes. Set TL/BR based on y order first... - *tlIndex = pos0.y > pos3.y ? 2 : 0; - *brIndex = pos0.y > pos3.y ? 0 : 2; - // And if it's horizontally flipped, trade to the actual TL/BR. - if (pos0.x > pos1.x) { - *tlIndex ^= 1; - *brIndex ^= 1; - } + *tlIndex = tl; + *brIndex = br; - // Do we need to think about rotation? - if (!state.enableTextures) - return true; + int tr = 1, bl = 1; + for (int i = 0; i < 4; ++i) { + if (i == tl || i == br) + continue; - const auto &textl = data[*tlIndex].v.texturecoords, &textr = data[*tlIndex ^ 1].v.texturecoords; - const auto &texbl = data[*brIndex ^ 1].v.texturecoords, &texbr = data[*brIndex].v.texturecoords; + if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y >= data[tl].v.screenpos.y) + bl = i; + if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y <= data[br].v.screenpos.y) + tr = i; + } - if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { - // Okay, the texture is also good, but let's avoid rotation issues. - const auto &postl = data[*tlIndex].v.screenpos; - const auto &posbr = data[*brIndex].v.screenpos; - return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; - } + // Must have found each of the coordinates. + if (tl + tr + bl + br != 6) + return false; + + // Note the common case is a single TL-TR-BR-BL. + const auto &postl = data[tl].v.screenpos, &postr = data[tr].v.screenpos; + const auto &posbr = data[br].v.screenpos, &posbl = data[bl].v.screenpos; + if (postl.x == posbl.x && postr.x == posbr.x && postl.y == postr.y && posbl.y == posbr.y) { + // Do we need to think about rotation? + if (!state.enableTextures) + return true; + + const auto &textl = data[tl].v.texturecoords, &textr = data[tr].v.texturecoords; + const auto &texbl = data[bl].v.texturecoords, &texbr = data[br].v.texturecoords; + + if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { + // Okay, the texture is also good, but let's avoid rotation issues. + return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; } } @@ -524,10 +683,13 @@ bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData * } bool DetectRectangleFromPair(const RasterizerState &state, const ClipVertexData data[6], int *tlIndex, int *brIndex) { + if (!IsCoordRectangleCompatible(state, data[0])) + return false; + // Color and Z must be flat. Also find the TL and BR meanwhile. int tl = 0, br = 0; for (int i = 1; i < 6; ++i) { - if (!AreCoordsRectangleCompatible(state, data[i], data[0])) + if (!AreCoordsRectangleCompatible(state, data[0], data[i])) return false; if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y) diff --git a/GPU/Software/RasterizerRectangle.h b/GPU/Software/RasterizerRectangle.h index 19e4b42b48..49f2e61c93 100644 --- a/GPU/Software/RasterizerRectangle.h +++ b/GPU/Software/RasterizerRectangle.h @@ -21,7 +21,7 @@ namespace Rasterizer { void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state); bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex); - bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex); + bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex); bool DetectRectangleFromPair(const RasterizerState &state, const ClipVertexData data[6], int *tlIndex, int *brIndex); bool DetectRectangleThroughModeSlices(const RasterizerState &state, const ClipVertexData data[4]); } diff --git a/GPU/Software/RasterizerRegCache.cpp b/GPU/Software/RasterizerRegCache.cpp index dbd0310fe4..7806b43e03 100644 --- a/GPU/Software/RasterizerRegCache.cpp +++ b/GPU/Software/RasterizerRegCache.cpp @@ -420,7 +420,7 @@ int CodeBlock::WriteProlog(int extraStack, const std::vector &vec #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) using namespace Gen; - BeginWrite(); + BeginWrite(32768); AlignCode16(); lastPrologStart_ = GetWritableCodePtr(); diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index fa3b1a730f..c748260dd4 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -25,6 +25,7 @@ #include "Core/Reporting.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/GPUState.h" +#include "GPU/Software/BinManager.h" #include "GPU/Software/Rasterizer.h" #include "GPU/Software/RasterizerRegCache.h" #include "GPU/Software/Sampler.h" @@ -38,8 +39,8 @@ using namespace Rasterizer; namespace Sampler { -static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); static Vec4IntResult SOFTRAST_CALL SampleFetch(int u, int v, const u8 *tptr, int bufw, int level, const SamplerID &samplerID); std::mutex jitCacheLock; @@ -49,6 +50,10 @@ void Init() { jitCache = new SamplerJitCache(); } +void FlushJit() { + jitCache->Flush(); +} + void Shutdown() { delete jitCache; jitCache = nullptr; @@ -63,9 +68,9 @@ bool DescribeCodePtr(const u8 *ptr, std::string &name) { return true; } -NearestFunc GetNearestFunc(SamplerID id) { +NearestFunc GetNearestFunc(SamplerID id, BinManager *binner) { id.linear = false; - NearestFunc jitted = jitCache->GetNearest(id); + NearestFunc jitted = jitCache->GetNearest(id, binner); if (jitted) { return jitted; } @@ -73,9 +78,9 @@ NearestFunc GetNearestFunc(SamplerID id) { return &SampleNearest; } -LinearFunc GetLinearFunc(SamplerID id) { +LinearFunc GetLinearFunc(SamplerID id, BinManager *binner) { id.linear = true; - LinearFunc jitted = jitCache->GetLinear(id); + LinearFunc jitted = jitCache->GetLinear(id, binner); if (jitted) { return jitted; } @@ -83,9 +88,9 @@ LinearFunc GetLinearFunc(SamplerID id) { return &SampleLinear; } -FetchFunc GetFetchFunc(SamplerID id) { +FetchFunc GetFetchFunc(SamplerID id, BinManager *binner) { id.fetch = true; - FetchFunc jitted = jitCache->GetFetch(id); + FetchFunc jitted = jitCache->GetFetch(id, binner); if (jitted) { return jitted; } @@ -93,13 +98,21 @@ FetchFunc GetFetchFunc(SamplerID id) { return &SampleFetch; } +thread_local SamplerJitCache::LastCache SamplerJitCache::lastFetch_; +thread_local SamplerJitCache::LastCache SamplerJitCache::lastNearest_; +thread_local SamplerJitCache::LastCache SamplerJitCache::lastLinear_; + // 256k should be enough. -SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4) { +SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4), cache_(64) { + lastFetch_.gen = -1; + lastNearest_.gen = -1; + lastLinear_.gen = -1; } void SamplerJitCache::Clear() { + clearGen_++; CodeBlock::Clear(); - cache_.clear(); + cache_.Clear(); addresses_.clear(); const10All16_ = nullptr; @@ -138,52 +151,85 @@ std::string SamplerJitCache::DescribeCodePtr(const u8 *ptr) { return CodeBlock::DescribeCodePtr(ptr); } -NearestFunc SamplerJitCache::GetNearest(const SamplerID &id) { - std::lock_guard guard(jitCacheLock); - - auto it = cache_.find(id); - if (it != cache_.end()) - return (NearestFunc)it->second; - - Compile(id); - - // Okay, should be there now. - it = cache_.find(id); - if (it != cache_.end()) - return (NearestFunc)it->second; - return nullptr; +void SamplerJitCache::Flush() { + std::unique_lock guard(jitCacheLock); + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } + compileQueue_.clear(); } -LinearFunc SamplerJitCache::GetLinear(const SamplerID &id) { - std::lock_guard guard(jitCacheLock); +NearestFunc SamplerJitCache::GetByID(const SamplerID &id, size_t key, BinManager *binner) { + std::unique_lock guard(jitCacheLock); + auto it = cache_.Get(key); + if (it != nullptr) + return it; - auto it = cache_.find(id); - if (it != cache_.end()) - return (LinearFunc)it->second; + if (!binner) { + // Can't compile, let's try to do it later when there's an opportunity. + compileQueue_.insert(id); + return nullptr; + } - Compile(id); + guard.unlock(); + binner->Flush("compile"); + guard.lock(); + + for (const auto &queued : compileQueue_) { + // Might've been compiled after enqueue, but before now. + size_t queuedKey = std::hash()(queued); + if (!cache_.Get(queuedKey)) + Compile(queued); + } + compileQueue_.clear(); + + if (!cache_.Get(key)) + Compile(id); // Okay, should be there now. - it = cache_.find(id); - if (it != cache_.end()) - return (LinearFunc)it->second; - return nullptr; + return cache_.Get(key); } -FetchFunc SamplerJitCache::GetFetch(const SamplerID &id) { - std::lock_guard guard(jitCacheLock); +NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, BinManager *binner) { + if (!g_Config.bSoftwareRenderingJit) + return nullptr; - auto it = cache_.find(id); - if (it != cache_.end()) - return (FetchFunc)it->second; + const size_t key = std::hash()(id); + if (lastNearest_.Match(key, clearGen_)) + return (NearestFunc)lastNearest_.func; - Compile(id); + auto func = GetByID(id, key, binner); + lastNearest_.Set(key, func, clearGen_); + return (NearestFunc)func; +} - // Okay, should be there now. - it = cache_.find(id); - if (it != cache_.end()) - return (FetchFunc)it->second; - return nullptr; +LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, BinManager *binner) { + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + + const size_t key = std::hash()(id); + if (lastLinear_.Match(key, clearGen_)) + return (LinearFunc)lastLinear_.func; + + auto func = GetByID(id, key, binner); + lastLinear_.Set(key, func, clearGen_); + return (LinearFunc)func; +} + +FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, BinManager *binner) { + if (!g_Config.bSoftwareRenderingJit) + return nullptr; + + const size_t key = std::hash()(id); + if (lastFetch_.Match(key, clearGen_)) + return (FetchFunc)lastFetch_.func; + + auto func = GetByID(id, key, binner); + lastFetch_.Set(key, func, clearGen_); + return (FetchFunc)func; } void SamplerJitCache::Compile(const SamplerID &id) { @@ -195,25 +241,23 @@ void SamplerJitCache::Compile(const SamplerID &id) { // We compile them together so the cache can't possibly be cleared in between. // We might vary between nearest and linear, so we can't clear between. #if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP) - if (g_Config.bSoftwareRenderingJit) { - SamplerID fetchID = id; - fetchID.linear = false; - fetchID.fetch = true; - addresses_[fetchID] = GetCodePointer(); - cache_[fetchID] = (NearestFunc)CompileFetch(fetchID); + SamplerID fetchID = id; + fetchID.linear = false; + fetchID.fetch = true; + addresses_[fetchID] = GetCodePointer(); + cache_.Insert(std::hash()(fetchID), (NearestFunc)CompileFetch(fetchID)); - SamplerID nearestID = id; - nearestID.linear = false; - nearestID.fetch = false; - addresses_[nearestID] = GetCodePointer(); - cache_[nearestID] = (NearestFunc)CompileNearest(nearestID); + SamplerID nearestID = id; + nearestID.linear = false; + nearestID.fetch = false; + addresses_[nearestID] = GetCodePointer(); + cache_.Insert(std::hash()(nearestID), (NearestFunc)CompileNearest(nearestID)); - SamplerID linearID = id; - linearID.linear = true; - linearID.fetch = false; - addresses_[linearID] = GetCodePointer(); - cache_[linearID] = (NearestFunc)CompileLinear(linearID); - } + SamplerID linearID = id; + linearID.linear = true; + linearID.fetch = false; + addresses_[linearID] = GetCodePointer(); + cache_.Insert(std::hash()(linearID), (NearestFunc)CompileLinear(linearID)); #endif } @@ -416,7 +460,7 @@ static inline void ApplyTexelClamp(int out_u[N], int out_v[N], const int u[N], c } } -static inline void GetTexelCoordinates(int level, float s, float t, int &out_u, int &out_v, int x, int y, const SamplerID &samplerID) { +static inline void GetTexelCoordinates(int level, float s, float t, int &out_u, int &out_v, const SamplerID &samplerID) { int width = samplerID.cached.sizes[level].w; int height = samplerID.cached.sizes[level].h; @@ -535,15 +579,15 @@ Vec4IntResult SOFTRAST_CALL GetTextureFunctionOutput(Vec4IntArg prim_color_in, V return ToVec4IntResult(Vec4(out_rgb, out_a)); } -static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID) { +static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID) { int u, v; // Nearest filtering only. Round texcoords. - GetTexelCoordinates(level, s, t, u, v, x, y, samplerID); + GetTexelCoordinates(level, s, t, u, v, samplerID); Vec4 c0 = Vec4::FromRGBA(SampleNearest<1>(&u, &v, tptr[0], bufw[0], level, samplerID).v[0]); if (levelFrac) { - GetTexelCoordinates(level + 1, s, t, u, v, x, y, samplerID); + GetTexelCoordinates(level + 1, s, t, u, v, samplerID); Vec4 c1 = Vec4::FromRGBA(SampleNearest<1>(&u, &v, tptr[1], bufw[1], level + 1, samplerID).v[0]); c0 = (c1 * levelFrac + c0 * (16 - levelFrac)) / 16; @@ -609,7 +653,7 @@ static inline Vec4IntResult SOFTRAST_CALL ApplyTexelClampQuadT(bool clamp, int v #endif } -static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadS(int level, float in_s, int &frac_u, int x, const SamplerID &samplerID) { +static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadS(int level, float in_s, int &frac_u, const SamplerID &samplerID) { int width = samplerID.cached.sizes[level].w; int base_u = (int)(in_s * width * 256) - 128; @@ -620,7 +664,7 @@ static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadS(int level, fl return ApplyTexelClampQuadS(samplerID.clampS, base_u, width); } -static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadT(int level, float in_t, int &frac_v, int y, const SamplerID &samplerID) { +static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadT(int level, float in_t, int &frac_v, const SamplerID &samplerID) { int height = samplerID.cached.sizes[level].h; int base_v = (int)(in_t * height * 256) - 128; @@ -631,10 +675,10 @@ static inline Vec4IntResult SOFTRAST_CALL GetTexelCoordinatesQuadT(int level, fl return ApplyTexelClampQuadT(samplerID.clampT, base_v, height); } -static Vec4IntResult SOFTRAST_CALL SampleLinearLevel(float s, float t, int x, int y, const u8 *const *tptr, const uint16_t *bufw, int texlevel, const SamplerID &samplerID) { +static Vec4IntResult SOFTRAST_CALL SampleLinearLevel(float s, float t, const u8 *const *tptr, const uint16_t *bufw, int texlevel, const SamplerID &samplerID) { int frac_u, frac_v; - const Vec4 u = GetTexelCoordinatesQuadS(texlevel, s, frac_u, x, samplerID); - const Vec4 v = GetTexelCoordinatesQuadT(texlevel, t, frac_v, y, samplerID); + const Vec4 u = GetTexelCoordinatesQuadS(texlevel, s, frac_u, samplerID); + const Vec4 v = GetTexelCoordinatesQuadT(texlevel, t, frac_v, samplerID); Nearest4 c = SampleNearest<4>(u.AsArray(), v.AsArray(), tptr[0], bufw[0], texlevel, samplerID); Vec4 texcolor_tl = Vec4::FromRGBA(c.v[0]); @@ -646,10 +690,10 @@ static Vec4IntResult SOFTRAST_CALL SampleLinearLevel(float s, float t, int x, in return ToVec4IntResult((top * (0x10 - frac_v) + bot * frac_v) / (16 * 16)); } -static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int texlevel, int levelFrac, const SamplerID &samplerID) { - Vec4 c0 = SampleLinearLevel(s, t, x, y, tptr, bufw, texlevel, samplerID); +static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int texlevel, int levelFrac, const SamplerID &samplerID) { + Vec4 c0 = SampleLinearLevel(s, t, tptr, bufw, texlevel, samplerID); if (levelFrac) { - const Vec4 c1 = SampleLinearLevel(s, t, x, y, tptr + 1, bufw + 1, texlevel + 1, samplerID); + const Vec4 c1 = SampleLinearLevel(s, t, tptr + 1, bufw + 1, texlevel + 1, samplerID); c0 = (c1 * levelFrac + c0 * (16 - levelFrac)) / 16; } return GetTextureFunctionOutput(prim_color, ToVec4IntArg(c0), samplerID); diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 9af945a9f2..fbe606b110 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -20,10 +20,14 @@ #include "ppsspp_config.h" #include +#include +#include "Common/Data/Collections/Hashmaps.h" #include "GPU/Math3D.h" #include "GPU/Software/FuncId.h" #include "GPU/Software/RasterizerRegCache.h" +class BinManager; + namespace Sampler { // Our std::unordered_map argument will ignore the alignment attribute, but that doesn't matter. @@ -34,15 +38,16 @@ namespace Sampler { #endif typedef Rasterizer::Vec4IntResult(SOFTRAST_CALL *FetchFunc)(int u, int v, const u8 *tptr, int bufw, int level, const SamplerID &samplerID); -FetchFunc GetFetchFunc(SamplerID id); +FetchFunc GetFetchFunc(SamplerID id, BinManager *binner); -typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, int x, int y, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -NearestFunc GetNearestFunc(SamplerID id); +typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +NearestFunc GetNearestFunc(SamplerID id, BinManager *binner); -typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, int x, int y, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); -LinearFunc GetLinearFunc(SamplerID id); +typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, Rasterizer::Vec4IntArg prim_color, const u8 *const *tptr, const uint16_t *bufw, int level, int levelFrac, const SamplerID &samplerID); +LinearFunc GetLinearFunc(SamplerID id, BinManager *binner); void Init(); +void FlushJit(); void Shutdown(); bool DescribeCodePtr(const u8 *ptr, std::string &name); @@ -52,15 +57,17 @@ public: SamplerJitCache(); // Returns a pointer to the code to run. - NearestFunc GetNearest(const SamplerID &id); - LinearFunc GetLinear(const SamplerID &id); - FetchFunc GetFetch(const SamplerID &id); + NearestFunc GetNearest(const SamplerID &id, BinManager *binner); + LinearFunc GetLinear(const SamplerID &id, BinManager *binner); + FetchFunc GetFetch(const SamplerID &id, BinManager *binner); void Clear() override; + void Flush(); std::string DescribeCodePtr(const u8 *ptr) override; private: void Compile(const SamplerID &id); + NearestFunc GetByID(const SamplerID &id, size_t key, BinManager *binner); FetchFunc CompileFetch(const SamplerID &id); NearestFunc CompileNearest(const SamplerID &id); LinearFunc CompileLinear(const SamplerID &id); @@ -121,8 +128,29 @@ private: const u8 *const5551Swizzle_ = nullptr; const u8 *const5650Swizzle_ = nullptr; - std::unordered_map cache_; + struct LastCache { + size_t key; + NearestFunc func; + int gen = -1; + + bool Match(size_t k, int g) const { + return key == k && gen == g; + } + + void Set(size_t k, NearestFunc f, int g) { + key = k; + func = f; + gen = g; + } + }; + + DenseHashMap cache_; std::unordered_map addresses_; + std::unordered_set compileQueue_; + int clearGen_ = 0; + static thread_local LastCache lastFetch_; + static thread_local LastCache lastNearest_; + static thread_local LastCache lastLinear_; }; #if defined(__clang__) || defined(__GNUC__) diff --git a/GPU/Software/SamplerX86.cpp b/GPU/Software/SamplerX86.cpp index 150856f6f5..290f8587f4 100644 --- a/GPU/Software/SamplerX86.cpp +++ b/GPU/Software/SamplerX86.cpp @@ -45,7 +45,7 @@ FetchFunc SamplerJitCache::CompileFetch(const SamplerID &id) { regCache_.ForceRetain(RegCache::GEN_RESULT); regCache_.ChangeReg(XMM0, RegCache::VEC_RESULT); - BeginWrite(); + BeginWrite(2048); Describe("Init"); const u8 *start = AlignCode16(); @@ -122,7 +122,7 @@ FetchFunc SamplerJitCache::CompileFetch(const SamplerID &id) { NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { _assert_msg_(!id.fetch && !id.linear, "Fetch and linear should be cleared on sampler id"); - BeginWrite(); + BeginWrite(2048); Describe("Init"); // Let's drop some helpful constants here. @@ -133,8 +133,6 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { regCache_.SetupABI({ RegCache::VEC_ARG_S, RegCache::VEC_ARG_T, - RegCache::GEN_ARG_X, - RegCache::GEN_ARG_Y, RegCache::VEC_ARG_COLOR, RegCache::GEN_ARG_TEXPTR_PTR, RegCache::GEN_ARG_BUFW_PTR, @@ -144,16 +142,16 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { }); #if PPSSPP_PLATFORM(WINDOWS) - // RET + shadow space + 8 byte space for color arg (the Win32 ABI is kinda ugly.) - stackArgPos_ = 8 + 32 + 8; + // RET + shadow space. + stackArgPos_ = 8 + 32; - // Positions: stackArgPos_+0=src, stackArgPos_+8=bufw, stackArgPos_+16=level, stackArgPos_+24=levelFrac - stackIDOffset_ = 32; - stackLevelOffset_ = 16; + // Positions: stackArgPos_+0=bufwptr, stackArgPos_+8=level, stackArgPos_+16=levelFrac + stackIDOffset_ = 24; + stackLevelOffset_ = 8; #else stackArgPos_ = 0; - // This is the only arg that went to the stack, it's after the RET. - stackIDOffset_ = 8; + // No args on the stack. + stackIDOffset_ = -1; stackLevelOffset_ = -1; #endif @@ -182,23 +180,20 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { if (!id.hasAnyMips && regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) regCache_.ForceRelease(RegCache::GEN_ARG_LEVELFRAC); - if (regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { - // On Linux, RCX is currently bufwptr, but we'll need it for other things. + if (regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) { + // On Linux, RCX is currently levelFrac, but we'll need it for other things. if (!cpu_info.bBMI2) { - X64Reg bufwReg = regCache_.Find(RegCache::GEN_ARG_BUFW_PTR); - MOV(64, R(R15), R(bufwReg)); - regCache_.Unlock(bufwReg, RegCache::GEN_ARG_BUFW_PTR); - regCache_.ForceRelease(RegCache::GEN_ARG_BUFW_PTR); - regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); - regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); + X64Reg levelFracReg = regCache_.Find(RegCache::GEN_ARG_LEVELFRAC); + MOV(64, R(R15), R(levelFracReg)); + regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); + regCache_.ForceRelease(RegCache::GEN_ARG_LEVELFRAC); + regCache_.ChangeReg(R15, RegCache::GEN_ARG_LEVELFRAC); + regCache_.ForceRetain(RegCache::GEN_ARG_LEVELFRAC); } - } else { - // Let's load bufwptr/texptrptr into regs. Match Linux just for consistency - RDX is free. + } else if (!regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { + // Let's load bufwptr into regs. RDX is free. MOV(64, R(RDX), MDisp(RSP, stackArgPos_ + 0)); - MOV(64, R(R15), MDisp(RSP, stackArgPos_ + 8)); - regCache_.ChangeReg(RDX, RegCache::GEN_ARG_TEXPTR_PTR); - regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); - regCache_.ForceRetain(RegCache::GEN_ARG_TEXPTR_PTR); + regCache_.ChangeReg(RDX, RegCache::GEN_ARG_BUFW_PTR); regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); } // Okay, now lock RCX as a shifting reg. @@ -284,7 +279,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { CMP(8, R(levelFracReg), Imm8(0)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); } else { - CMP(8, MDisp(RSP, stackArgPos_ + 24), Imm8(0)); + CMP(8, MDisp(RSP, stackArgPos_ + 16), Imm8(0)); } FixupBranch skip = J_CC(CC_Z, true); @@ -295,7 +290,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { regCache_.Unlock(levelReg, RegCache::GEN_ARG_LEVEL); } else { // It's fine to just modify this in place. - ADD(32, MDisp(RSP, stackArgPos_ + 16), Imm8(1)); + ADD(32, MDisp(RSP, stackArgPos_ + stackLevelOffset_), Imm8(1)); } // This is inside the conditional, but it's okay because we throw it away after. @@ -357,7 +352,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { Describe("BlendMips"); if (!regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) { X64Reg levelFracReg = regCache_.Alloc(RegCache::GEN_ARG_LEVELFRAC); - MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 24)); + MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 16)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); regCache_.ForceRetain(RegCache::GEN_ARG_LEVELFRAC); } @@ -413,6 +408,8 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { } regCache_.ForceRelease(RegCache::VEC_RESULT); + if (regCache_.Has(RegCache::GEN_ARG_ID)) + regCache_.ForceRelease(RegCache::GEN_ARG_ID); if (!success) { regCache_.Reset(false); @@ -441,7 +438,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { _assert_msg_(id.linear && !id.fetch, "Only linear should be set on sampler id"); - BeginWrite(); + BeginWrite(2048); Describe("Init"); // We don't use stackArgPos_ here, this is just for DXT. @@ -525,8 +522,6 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.SetupABI({ RegCache::VEC_ARG_S, RegCache::VEC_ARG_T, - RegCache::GEN_ARG_X, - RegCache::GEN_ARG_Y, RegCache::VEC_ARG_COLOR, RegCache::GEN_ARG_TEXPTR_PTR, RegCache::GEN_ARG_BUFW_PTR, @@ -536,22 +531,21 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { }); #if PPSSPP_PLATFORM(WINDOWS) - // RET + shadow space + 8 byte space for color arg (the Win32 ABI is kinda ugly.) - stackArgPos_ = 8 + 32 + 8; + // RET + shadow space. + stackArgPos_ = 8 + 32; // Free up some more vector regs on Windows too, where we're a bit tight. stackArgPos_ += WriteProlog(0, { XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12 }, { R15, R14, R13, R12 }); - // Positions: stackArgPos_+0=src, stackArgPos_+8=bufw, stackArgPos_+16=level, stackArgPos_+24=levelFrac - stackIDOffset_ = 32; - stackLevelOffset_ = 16; + // Positions: stackArgPos_+0=bufwptr, stackArgPos_+8=level, stackArgPos_+16=levelFrac + stackIDOffset_ = 24; + stackLevelOffset_ = 8; - // If needed, we could store UV1 data in shadow space, but we no longer due. + // If needed, we could store UV1 data in shadow space, but we no longer do. stackUV1Offset_ = -8; #else stackArgPos_ = 0; stackArgPos_ += WriteProlog(0, {}, { R15, R14, R13, R12 }); - // Just after the RET. - stackIDOffset_ = 8; + stackIDOffset_ = -1; stackLevelOffset_ = -1; // Use the red zone. @@ -591,8 +585,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { } // We also want to save src and bufw for later. Might be in a reg already. - if (regCache_.Has(RegCache::GEN_ARG_TEXPTR_PTR)) { - _assert_(regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)); + if (regCache_.Has(RegCache::GEN_ARG_TEXPTR_PTR) && regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { X64Reg srcReg = regCache_.Find(RegCache::GEN_ARG_TEXPTR_PTR); X64Reg bufwReg = regCache_.Find(RegCache::GEN_ARG_BUFW_PTR); MOV(64, R(R14), R(srcReg)); @@ -601,6 +594,12 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.Unlock(bufwReg, RegCache::GEN_ARG_BUFW_PTR); regCache_.ForceRelease(RegCache::GEN_ARG_TEXPTR_PTR); regCache_.ForceRelease(RegCache::GEN_ARG_BUFW_PTR); + } else if (regCache_.Has(RegCache::GEN_ARG_TEXPTR_PTR)) { + X64Reg srcReg = regCache_.Find(RegCache::GEN_ARG_TEXPTR_PTR); + MOV(64, R(R14), R(srcReg)); + regCache_.Unlock(srcReg, RegCache::GEN_ARG_TEXPTR_PTR); + regCache_.ForceRelease(RegCache::GEN_ARG_TEXPTR_PTR); + MOV(64, R(R15), MDisp(RSP, stackArgPos_ + 0)); } else { MOV(64, R(R14), MDisp(RSP, stackArgPos_ + 0)); MOV(64, R(R15), MDisp(RSP, stackArgPos_ + 8)); @@ -608,9 +607,11 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { // Okay, and now remember we moved to R14/R15. regCache_.ChangeReg(R14, RegCache::GEN_ARG_TEXPTR_PTR); - regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); regCache_.ForceRetain(RegCache::GEN_ARG_TEXPTR_PTR); - regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); + if (!regCache_.Has(RegCache::GEN_ARG_BUFW_PTR)) { + regCache_.ChangeReg(R15, RegCache::GEN_ARG_BUFW_PTR); + regCache_.ForceRetain(RegCache::GEN_ARG_BUFW_PTR); + } bool success = true; @@ -758,7 +759,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { CMP(8, R(levelFracReg), Imm8(0)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); } else { - CMP(8, MDisp(RSP, stackArgPos_ + 24), Imm8(0)); + CMP(8, MDisp(RSP, stackArgPos_ + 16), Imm8(0)); } FixupBranch skip = J_CC(CC_Z, true); @@ -769,7 +770,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.Unlock(levelReg, RegCache::GEN_ARG_LEVEL); } else { // It's fine to just modify this in place. - ADD(32, MDisp(RSP, stackArgPos_ + 16), Imm8(1)); + ADD(32, MDisp(RSP, stackArgPos_ + stackLevelOffset_), Imm8(1)); } if (nearest != nullptr) { @@ -808,7 +809,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { Describe("BlendMips"); if (!regCache_.Has(RegCache::GEN_ARG_LEVELFRAC)) { X64Reg levelFracReg = regCache_.Alloc(RegCache::GEN_ARG_LEVELFRAC); - MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 24)); + MOVZX(32, 8, levelFracReg, MDisp(RSP, stackArgPos_ + 16)); regCache_.Unlock(levelFracReg, RegCache::GEN_ARG_LEVELFRAC); regCache_.ForceRetain(RegCache::GEN_ARG_LEVELFRAC); } @@ -870,6 +871,8 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { } regCache_.ForceRelease(RegCache::VEC_RESULT); + if (regCache_.Has(RegCache::GEN_ARG_ID)) + regCache_.ForceRelease(RegCache::GEN_ARG_ID); if (!success) { regCache_.Reset(false); @@ -1223,9 +1226,9 @@ bool SamplerJitCache::Jit_ReadClutQuad(const SamplerID &id, bool level1) { } else { #if PPSSPP_PLATFORM(WINDOWS) if (cpu_info.bAVX2) { - VPBROADCASTD(128, vecLevelReg, MDisp(RSP, stackArgPos_ + 16)); + VPBROADCASTD(128, vecLevelReg, MDisp(RSP, stackArgPos_ + stackLevelOffset_)); } else { - MOVD_xmm(vecLevelReg, MDisp(RSP, stackArgPos_ + 16)); + MOVD_xmm(vecLevelReg, MDisp(RSP, stackArgPos_ + stackLevelOffset_)); PSHUFD(vecLevelReg, R(vecLevelReg), _MM_SHUFFLE(0, 0, 0, 0)); } #else @@ -2583,11 +2586,6 @@ bool SamplerJitCache::Jit_GetTexDataSwizzled(const SamplerID &id, int bitsPerTex bool SamplerJitCache::Jit_GetTexelCoords(const SamplerID &id) { Describe("Texel"); - // First, adjust X and Y... - // TODO: Shouldn't do this in the sampler, need to get s/t right. - regCache_.ForceRelease(RegCache::GEN_ARG_X); - regCache_.ForceRelease(RegCache::GEN_ARG_Y); - X64Reg uReg = regCache_.Alloc(RegCache::GEN_ARG_U); X64Reg vReg = regCache_.Alloc(RegCache::GEN_ARG_V); X64Reg sReg = regCache_.Find(RegCache::VEC_ARG_S); @@ -2602,7 +2600,7 @@ bool SamplerJitCache::Jit_GetTexelCoords(const SamplerID &id) { levelReg = regCache_.Find(RegCache::GEN_ARG_LEVEL); } else { levelReg = regCache_.Alloc(RegCache::GEN_ARG_LEVEL); - MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + 16)); + MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + stackLevelOffset_)); } // We'll multiply these at the same time, so it's nice to put together. @@ -2774,7 +2772,7 @@ bool SamplerJitCache::Jit_GetTexelCoordsQuad(const SamplerID &id) { } else { releaseLevelReg = true; levelReg = regCache_.Alloc(RegCache::GEN_ARG_LEVEL); - MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + 16)); + MOV(32, R(levelReg), MDisp(RSP, stackArgPos_ + stackLevelOffset_)); } // This will load the current and next level's sizes, 16x4. @@ -2826,8 +2824,6 @@ bool SamplerJitCache::Jit_GetTexelCoordsQuad(const SamplerID &id) { PSLLD(tempXYReg, 7); PADDD(sReg, R(tempXYReg)); regCache_.Release(tempXYReg, RegCache::VEC_TEMP0); - regCache_.ForceRelease(RegCache::GEN_ARG_X); - regCache_.ForceRelease(RegCache::GEN_ARG_Y); // We do want the fraction, though, so extract that to an XMM for later. X64Reg allFracReg = INVALID_REG; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index ba6da9455c..9f70441692 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -29,6 +29,7 @@ #include "Core/Core.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/MemMap.h" +#include "Core/MemMapHelpers.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceGe.h" #include "Core/MIPS/MIPS.h" @@ -106,7 +107,7 @@ const SoftwareCommandTableEntry softgpuCommandTable[] = { { GE_CMD_FOG1, 0, SoftDirty::TRANSFORM_FOG }, { GE_CMD_FOG2, 0, SoftDirty::TRANSFORM_FOG }, - { GE_CMD_CLEARMODE, 0, SoftDirty::TRANSFORM_BASIC | SoftDirty::RAST_TEX | SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::PIXEL_BASIC | SoftDirty::PIXEL_ALPHA | SoftDirty::PIXEL_STENCIL | SoftDirty::PIXEL_CACHED | SoftDirty::BINNER_RANGE | SoftDirty::BINNER_OVERLAP }, + { GE_CMD_CLEARMODE, 0, SoftDirty::TRANSFORM_BASIC | SoftDirty::RAST_BASIC | SoftDirty::RAST_TEX | SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::PIXEL_BASIC | SoftDirty::PIXEL_ALPHA | SoftDirty::PIXEL_STENCIL | SoftDirty::PIXEL_CACHED | SoftDirty::BINNER_RANGE | SoftDirty::BINNER_OVERLAP }, { GE_CMD_TEXTUREMAPENABLE, 0, SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::RAST_TEX | SoftDirty::TRANSFORM_BASIC | SoftDirty::BINNER_OVERLAP }, { GE_CMD_FOGENABLE, 0, SoftDirty::PIXEL_BASIC | SoftDirty::PIXEL_CACHED | SoftDirty::TRANSFORM_BASIC | SoftDirty::TRANSFORM_FOG | SoftDirty::TRANSFORM_MATRIX }, { GE_CMD_TEXMODE, 0, SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::RAST_TEX }, @@ -445,7 +446,10 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) presentation_ = new PresentationCommon(draw_); presentation_->SetLanguage(draw_->GetShaderLanguageDesc().shaderLanguage); } - Resized(); + + NotifyConfigChanged(); + NotifyRenderResized(); + NotifyDisplayResized(); } void SoftGPU::DeviceLost() { @@ -701,7 +705,7 @@ bool SoftGPU::ClearDirty(uint32_t addr, uint32_t bytes, SoftGPUVRAMDirty value) return result; } -void SoftGPU::Resized() { +void SoftGPU::NotifyRenderResized() { // Force the render params to 480x272 so other things work. if (g_Config.IsPortrait()) { PSP_CoreParameter().renderWidth = 272; @@ -710,13 +714,18 @@ void SoftGPU::Resized() { PSP_CoreParameter().renderWidth = 480; PSP_CoreParameter().renderHeight = 272; } +} +void SoftGPU::NotifyDisplayResized() { if (presentation_) { - presentation_->UpdateSize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); + presentation_->UpdateDisplaySize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + presentation_->UpdateRenderSize(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); presentation_->UpdatePostShader(); } } +void SoftGPU::NotifyConfigChanged() {} + void SoftGPU::FastRunLoop(DisplayList &list) { PROFILE_THIS_SCOPE("soft_runloop"); const auto *cmdInfo = softgpuCmdInfo; @@ -784,45 +793,21 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { int bpp = gstate.getTransferBpp(); + // Use height less one to account for width, which can be greater or less than stride. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t srcSize = height * srcStride * bpp; + const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp; const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const uint32_t dstSize = height * dstStride * bpp; + const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp; // Need to flush both source and target, so we overwrite properly. - drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height); - drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height); - - DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); - - if (srcStride == dstStride && (u32)width == srcStride) { - u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp; - u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp; - - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); - u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - memcpy(dstp, srcp, width * height * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * height * bpp); + if (Memory::IsValidRange(src, srcSize) && Memory::IsValidRange(dst, dstSize)) { + drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height); + drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height); } else { - for (int y = 0; y < height; y++) { - u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp; - u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp; - - const u8 *srcp = Memory::GetPointer(srcLineStartAddr); - u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr); - memcpy(dstp, srcp, width * bpp); - GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp); - } + drawEngine_->transformUnit.Flush("blockxfer_wrap"); } - if (MemBlockInfoDetailed(srcSize, dstSize)) { - const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); - } - - // TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate. - cyclesExecuted += ((height * width * bpp) * 16) / 10; + DoBlockTransfer(gstate_c.skipDrawReason); // Could theoretically dirty the framebuffer. MarkDirty(dst, dstSize, SoftGPUVRAMDirty::DIRTY | SoftGPUVRAMDirty::REALLY_DIRTY); @@ -1423,8 +1408,8 @@ bool SoftGPU::GetCurrentClut(GPUDebugBuffer &buffer) return true; } -bool SoftGPU::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) -{ +bool SoftGPU::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { + UpdateUVScaleOffset(); return drawEngine_->transformUnit.GetCurrentSimpleVertices(count, vertices, indices); } diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 6c317d89c9..508baa6d0e 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -149,7 +149,10 @@ public: void DeviceLost() override; void DeviceRestore() override; - void Resized() override; + void NotifyRenderResized() override; + void NotifyDisplayResized() override; + void NotifyConfigChanged() override; + void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override { primaryInfo = "Software"; fullInfo = "Software"; @@ -205,6 +208,8 @@ protected: void CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight); void ConvertTextureDescFrom16(Draw::TextureDesc &desc, int srcwidth, int srcheight, const uint16_t *overrideData = nullptr); + void BuildReportingInfo() override {} + private: void MarkDirty(uint32_t addr, uint32_t stride, uint32_t height, GEBufferFormat fmt, SoftGPUVRAMDirty value); void MarkDirty(uint32_t addr, uint32_t bytes, SoftGPUVRAMDirty value); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 7d1d28d07d..e109f6d87a 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -62,6 +62,11 @@ SoftwareDrawEngine::~SoftwareDrawEngine() { FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); } +void SoftwareDrawEngine::NotifyConfigChanged() { + DrawEngineCommon::NotifyConfigChanged(); + decOptions_.applySkinInDecode = true; +} + void SoftwareDrawEngine::DispatchFlush() { transformUnit.Flush("debug"); } @@ -72,7 +77,7 @@ void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds, } void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) { - uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), true); int flipCull = cullMode != gstate.getCullMode() ? 1 : 0; // TODO: For now, just setting all dirty. @@ -137,7 +142,7 @@ void SoftwareDrawEngine::DispatchSubmitImm(GEPrimitiveType prim, TransformedVert } VertexDecoder *SoftwareDrawEngine::FindVertexDecoder(u32 vtype) { - const u32 vertTypeID = (vtype & 0xFFFFFF) | (gstate.getUVGenMode() << 24); + const u32 vertTypeID = GetVertTypeID(vtype, gstate.getUVGenMode(), true); return DrawEngineCommon::GetVertexDecoder(vertTypeID); } @@ -157,7 +162,7 @@ ClipCoords TransformUnit::ViewToClip(const ViewCoords &coords) { return Vec3ByMatrix44(coords, gstate.projMatrix); } -template +template static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, bool *outside_range_flag) { ScreenCoords ret; @@ -168,7 +173,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, // This matches hardware tests - depth is clamped when this flag is on. if (depthClamp) { // Note: if the depth is clipped (z/w <= -1.0), the outside_range_flag should NOT be set, even for x and y. - if (writeOutsideFlag && coords.z > -coords.w && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) { + if ((alwaysCheckRange || coords.z > -coords.w) && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) { *outside_range_flag = true; } @@ -176,7 +181,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, scaled.z = 0.f; else if (scaled.z > 65535.0f) scaled.z = 65535.0f; - } else if (writeOutsideFlag && (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) { + } else if (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0 || scaled.z < 0.0f || scaled.z >= 65536.0f) { *outside_range_flag = true; } @@ -204,17 +209,13 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords &coords, bool * float z = coords.z * zScale / coords.w + zCenter; if (gstate.isDepthClampEnabled()) { - if (outside_range_flag) - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); + return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); } - if (outside_range_flag) - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); - return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); + return ClipToScreenInternal(Vec3f(x, y, z), coords, outside_range_flag); } -ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords) { - return ClipToScreenInternal(coords, nullptr); +ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag) { + return ClipToScreenInternal(coords, outsideRangeFlag); } ScreenCoords TransformUnit::DrawingToScreen(const DrawingCoords &coords, u16 z) { @@ -245,7 +246,6 @@ struct TransformState { bool enableLighting : 1; bool enableFog : 1; bool readUV : 1; - bool readWeights : 1; bool negateNormals : 1; uint8_t uvGenMode : 2; uint8_t matrixMode : 2; @@ -257,7 +257,6 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { state->enableLighting = gstate.isLightingEnabled(); state->enableFog = gstate.isFogEnabled(); state->readUV = !gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV(); - state->readWeights = vreader.skinningEnabled() && state->enableTransform; state->negateNormals = gstate.areNormalsReversed(); state->uvGenMode = gstate.getUVGenMode(); @@ -296,17 +295,34 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { if (state->enableFog) { float fogEnd = getFloat24(gstate.fog1); float fogSlope = getFloat24(gstate.fog2); - // Same fixup as in ShaderManagerGLES.cpp - if (my_isnanorinf(fogEnd)) { - fogEnd = std::signbit(fogEnd) ? -INFINITY : INFINITY; - } - if (my_isnanorinf(fogSlope)) { - fogSlope = std::signbit(fogSlope) ? -INFINITY : INFINITY; - } // We bake fog end and slope into the dot product. state->posToFog = Vec4f(worldview[2], worldview[6], worldview[10], worldview[14] + fogEnd); - state->posToFog *= fogSlope; + + // If either are NAN/INF, we simplify so there's no inf + -inf muddying things. + // This is required for Outrun to render proper skies, for example. + // The PSP treats these exponents as if they were valid. + if (my_isnanorinf(fogEnd)) { + bool sign = std::signbit(fogEnd); + // The multiply would reverse it if it wasn't infinity (doesn't matter if it's infnan.) + if (std::signbit(fogSlope)) + sign = !sign; + // Also allow a multiply by zero (slope) to result in zero, regardless of sign. + // Act like it was negative and clamped to zero. + if (fogSlope == 0.0f) + sign = true; + + // Since this is constant for the entire draw, we don't even use infinity. + float forced = sign ? 0.0f : 1.0f; + state->posToFog = Vec4f(0.0f, 0.0f, 0.0f, forced); + } else if (my_isnanorinf(fogSlope)) { + // We can't have signs differ with infinities, so we use a large value. + // Anything outside [0, 1] will clamp, so this essentially forces extremes. + fogSlope = std::signbit(fogSlope) ? -262144.0f : 262144.0f; + state->posToFog *= fogSlope; + } else { + state->posToFog *= fogSlope; + } } state->screenScale = Vec3f(gstate.getViewportXScale(), gstate.getViewportYScale(), gstate.getViewportZScale()); @@ -314,12 +330,12 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { } if (gstate.isDepthClampEnabled()) - state->roundToScreen = &ClipToScreenInternal; + state->roundToScreen = &ClipToScreenInternal; else - state->roundToScreen = &ClipToScreenInternal; + state->roundToScreen = &ClipToScreenInternal; } -ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformState &state) { +ClipVertexData TransformUnit::ReadVertex(const VertexReader &vreader, const TransformState &state) { PROFILE_THIS_SCOPE("read_vert"); // If we ever thread this, we'll have to change this. ClipVertexData vertex; @@ -337,41 +353,15 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS vertex.v.texturecoords = lastTC; } - Vec3f normal; static Vec3f lastnormal; - if (vreader.hasNormal()) { - vreader.ReadNrm(normal.AsArray()); - lastnormal = normal; - - if (state.negateNormals) - normal = -normal; - } else { - normal = lastnormal; - } - - if (state.readWeights) { - float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; - vreader.ReadWeights(W); - - Vec3 tmppos(0.f, 0.f, 0.f); - Vec3 tmpnrm(0.f, 0.f, 0.f); - - for (int i = 0; i < vreader.numBoneWeights(); ++i) { - Vec3 step = Vec3ByMatrix43(pos, gstate.boneMatrix + i * 12); - tmppos += step * W[i]; - if (vreader.hasNormal()) { - step = Norm3ByMatrix43(normal, gstate.boneMatrix + i * 12); - tmpnrm += step * W[i]; - } - } - - pos = tmppos; - if (vreader.hasNormal()) - normal = tmpnrm; - } + if (vreader.hasNormal()) + vreader.ReadNrm(lastnormal.AsArray()); + Vec3f normal = lastnormal; + if (state.negateNormals) + normal = -normal; if (vreader.hasColor0()) { - vreader.ReadColor0_8888((u8 *)&vertex.v.color0); + vertex.v.color0 = vreader.ReadColor0_8888(); } else { vertex.v.color0 = gstate.getMaterialAmbientRGBA(); } @@ -416,11 +406,9 @@ ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformS vertex.v.clipw = vertex.clippos.w; Vec3 worldnormal; - if (vreader.hasNormal()) { + if (state.enableLighting || state.uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP) { worldnormal = TransformUnit::ModelToWorldNormal(normal); worldnormal.NormalizeOr001(); - } else { - worldnormal = Vec3(0.0f, 0.0f, 1.0f); } // Time to generate some texture coords. Lighting will handle shade mapping. @@ -581,10 +569,9 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G // Some games send rectangles as a series of regular triangles. // We look for this, but only in throughmode. ClipVertexData buf[6]; - int buf_index = data_index_; - for (int i = 0; i < data_index_; ++i) { - buf[i] = data_[i]; - } + // Could start at data_index_ and copy to buf, but there's little reason. + int buf_index = 0; + _assert_(data_index_ == 0); for (int vtx = 0; vtx < vertex_count; ++vtx) { buf[buf_index++] = vreader.Read(vtx); @@ -793,7 +780,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G } int tl = -1, br = -1; - if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, vertex_count, &tl, &br)) { + if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, &tl, &br)) { Clipper::ProcessRect(data_[tl], data_[br], *binner_); break; } @@ -865,7 +852,7 @@ void TransformUnit::SubmitImmVertex(const ClipVertexData &vert, SoftwareDrawEngi break; } - uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode()); + uint32_t vertTypeID = GetVertTypeID(gstate.vertType | GE_VTYPE_POS_FLOAT, gstate.getUVGenMode(), true); // This now processes the step with shared logic, given the existing data_. isImmDraw_ = true; SubmitPrimitive(nullptr, nullptr, GE_PRIM_KEEP_PREVIOUS, 0, vertTypeID, nullptr, drawEngine); @@ -965,6 +952,7 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector coord, this is negative and force-scissors. @@ -149,7 +149,7 @@ public: SoftDirty GetDirty(); private: - ClipVertexData ReadVertex(VertexReader &vreader, const TransformState &state); + ClipVertexData ReadVertex(const VertexReader &vreader, const TransformState &state); void SendTriangle(CullType cullType, const ClipVertexData *verts, int provoking = 2); u8 *decoded_ = nullptr; @@ -171,6 +171,7 @@ public: SoftwareDrawEngine(); ~SoftwareDrawEngine(); + void NotifyConfigChanged() override; void DispatchFlush() override; void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int cullMode, int *bytesRead) override; void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) override; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index b0e88aa0f2..a8387e3720 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Profiler/Profiler.h" @@ -42,6 +43,7 @@ #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/ShaderUniforms.h" #include "GPU/Debugger/Debugger.h" #include "GPU/Vulkan/DrawEngineVulkan.h" #include "GPU/Vulkan/TextureCacheVulkan.h" @@ -61,19 +63,6 @@ enum { enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 }; -enum { - DRAW_BINDING_TEXTURE = 0, - DRAW_BINDING_2ND_TEXTURE = 1, - DRAW_BINDING_DEPAL_TEXTURE = 2, - DRAW_BINDING_DYNUBO_BASE = 3, - DRAW_BINDING_DYNUBO_LIGHT = 4, - DRAW_BINDING_DYNUBO_BONE = 5, - DRAW_BINDING_TESS_STORAGE_BUF = 6, - DRAW_BINDING_TESS_STORAGE_BUF_WU = 7, - DRAW_BINDING_TESS_STORAGE_BUF_WV = 8, - DRAW_BINDING_INPUT_ATTACHMENT = 9, -}; - enum { TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex) }; @@ -96,7 +85,7 @@ void DrawEngineVulkan::InitDeviceObjects() { // TODO: Make things more flexible, so we at least have specialized layouts for input attachments and tess. // Note that it becomes a support matrix.. - VkDescriptorSetLayoutBinding bindings[10]{}; + VkDescriptorSetLayoutBinding bindings[DRAW_BINDING_COUNT]{}; bindings[0].descriptorCount = 1; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; @@ -112,7 +101,7 @@ void DrawEngineVulkan::InitDeviceObjects() { bindings[3].descriptorCount = 1; bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; bindings[3].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - if (gstate_c.Supports(GPU_SUPPORTS_GS_CULLING)) + if (gstate_c.Use(GPU_USE_GS_CULLING)) bindings[3].stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT; bindings[3].binding = DRAW_BINDING_DYNUBO_BASE; bindings[4].descriptorCount = 1; @@ -136,6 +125,7 @@ void DrawEngineVulkan::InitDeviceObjects() { bindings[8].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bindings[8].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; bindings[8].binding = DRAW_BINDING_TESS_STORAGE_BUF_WV; + // Note: This binding is not included if !gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH), using bindingCount below. bindings[9].descriptorCount = 1; bindings[9].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; bindings[9].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; @@ -145,7 +135,7 @@ void DrawEngineVulkan::InitDeviceObjects() { VkDevice device = vulkan->GetDevice(); VkDescriptorSetLayoutCreateInfo dsl{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - dsl.bindingCount = ARRAY_SIZE(bindings); + dsl.bindingCount = gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH) ? ARRAY_SIZE(bindings) : ARRAY_SIZE(bindings) - 1; dsl.pBindings = bindings; VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_); _dbg_assert_(VK_SUCCESS == res); @@ -153,7 +143,7 @@ void DrawEngineVulkan::InitDeviceObjects() { static constexpr int DEFAULT_DESC_POOL_SIZE = 512; std::vector dpTypes; - dpTypes.resize(4); + dpTypes.resize(5); dpTypes[0].descriptorCount = DEFAULT_DESC_POOL_SIZE * 3; dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; dpTypes[1].descriptorCount = DEFAULT_DESC_POOL_SIZE * 3; // Don't use these for tess anymore, need max three per set. @@ -162,6 +152,8 @@ void DrawEngineVulkan::InitDeviceObjects() { dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; dpTypes[3].descriptorCount = DEFAULT_DESC_POOL_SIZE; // TODO: Use a separate layout when no spline stuff is needed to reduce the need for these. dpTypes[3].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + dpTypes[4].descriptorCount = DEFAULT_DESC_POOL_SIZE; // For the frame global uniform buffer. Might need to allocate multiple times. + dpTypes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; // Don't want to mess around with individually freeing these. @@ -184,9 +176,12 @@ void DrawEngineVulkan::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw_->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + VkDescriptorSetLayout layouts[2] = { frameDescSetLayout, descriptorSetLayout_}; + pl.setLayoutCount = ARRAY_SIZE(layouts); + pl.pSetLayouts = layouts; pl.flags = 0; + res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _dbg_assert_(VK_SUCCESS == res); @@ -211,6 +206,8 @@ void DrawEngineVulkan::InitDeviceObjects() { tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan); tessDataTransfer = tessDataTransferVulkan; + + draw_->SetInvalidationCallback(std::bind(&DrawEngineVulkan::Invalidate, this, std::placeholders::_1)); } DrawEngineVulkan::~DrawEngineVulkan() { @@ -241,7 +238,14 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { } void DrawEngineVulkan::DestroyDeviceObjects() { - VulkanContext *vulkan = draw_ ? (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT) : nullptr; + if (!draw_) { + // We've already done this from LostDevice. + return; + } + + VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + + draw_->SetInvalidationCallback(InvalidationCallback()); delete tessDataTransferVulkan; tessDataTransfer = nullptr; @@ -290,8 +294,6 @@ void DrawEngineVulkan::BeginFrame() { lastPipeline_ = nullptr; - lastRenderStepId_ = -1; - FrameData *frame = &GetCurFrame(); // First reset all buffers, then begin. This is so that Reset can free memory and Begin can allocate it, @@ -303,11 +305,13 @@ void DrawEngineVulkan::BeginFrame() { frame->pushIndex->Reset(); VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + frame->pushUBO->Begin(vulkan); frame->pushVertex->Begin(vulkan); frame->pushIndex->Begin(vulkan); - // TODO: How can we make this nicer... + frame->frameDescSetUpdated = false; + tessDataTransferVulkan->SetPushBuffer(frame->pushUBO); DirtyAllUBOs(); @@ -401,13 +405,13 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView // Didn't find one in the frame descriptor set cache, let's make a new one. // We wipe the cache on every frame. - VkDescriptorSet desc = frame.descPool.Allocate(1, &descriptorSetLayout_); + VkDescriptorSet desc = frame.descPool.Allocate(1, &descriptorSetLayout_, "game_descset"); // Even in release mode, this is bad. _assert_msg_(desc != VK_NULL_HANDLE, "Ran out of descriptor space in pool. sz=%d", (int)frame.descSets.size()); // We just don't write to the slots we don't care about, which is fine. - VkWriteDescriptorSet writes[9]{}; + VkWriteDescriptorSet writes[DRAW_BINDING_COUNT]{}; // Main texture int n = 0; VkDescriptorImageInfo tex[3]{}; @@ -541,6 +545,19 @@ void MarkUnreliable(VertexArrayInfoVulkan *vai) { // For now we just leave it in the pushbuffer. } +void DrawEngineVulkan::Invalidate(InvalidationCallbackFlags flags) { + if (flags & InvalidationCallbackFlags::COMMAND_BUFFER_STATE) { + GetCurFrame().frameDescSetUpdated = false; + } + if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) { + // If have a new render pass, dirty our dynamic state so it gets re-set. + // + // Dirty everything that has dynamic state that will need re-recording. + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + lastPipeline_ = nullptr; + } +} + // The inline wrapper in the header checks for numDrawCalls == 0 void DrawEngineVulkan::DoFlush() { VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); @@ -550,18 +567,6 @@ void DrawEngineVulkan::DoFlush() { gpuStats.numFlushes++; - // If have a new render pass, dirty our dynamic state so it gets re-set. - // We have to do this again after the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! - int curRenderStepId = renderManager->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - textureCache_->ForgetLastTexture(); - lastRenderStepId_ = curRenderStepId; - lastPipeline_ = nullptr; - } - bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE; bool textureNeedsApply = false; @@ -579,10 +584,6 @@ void DrawEngineVulkan::DoFlush() { // Always use software for flat shading to fix the provoking index. bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT); - VulkanVertexShader *vshader = nullptr; - VulkanFragmentShader *fshader = nullptr; - VulkanGeometryShader *gshader = nullptr; - uint32_t ibOffset; uint32_t vbOffset; @@ -595,7 +596,7 @@ void DrawEngineVulkan::DoFlush() { // Also avoid caching when software skinning. VkBuffer vbuf = VK_NULL_HANDLE; VkBuffer ibuf = VK_NULL_HANDLE; - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { useCache = false; } @@ -735,7 +736,7 @@ void DrawEngineVulkan::DoFlush() { break; } } else { - if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { + if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) { // If software skinning, we've already predecoded into "decoded". So push that content. VkDeviceSize size = decodedVerts_ * dec_->GetDecVtxFmt().stride; u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vbOffset, &vbuf); @@ -766,7 +767,7 @@ void DrawEngineVulkan::DoFlush() { textureCache_->ApplyTexture(); textureCache_->GetVulkanHandles(imageView, sampler); if (imageView == VK_NULL_HANDLE) - imageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::NULL_IMAGEVIEW); + imageView = (VkImageView)draw_->GetNativeObject(gstate_c.arrayTexture ? Draw::NativeObject::NULL_IMAGEVIEW_ARRAY : Draw::NativeObject::NULL_IMAGEVIEW); if (sampler == VK_NULL_HANDLE) sampler = nullSampler_; } @@ -776,30 +777,24 @@ void DrawEngineVulkan::DoFlush() { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform + VulkanVertexShader *vshader = nullptr; + VulkanFragmentShader *fshader = nullptr; + VulkanGeometryShader *gshader = nullptr; + + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode); if (!vshader) { // We're screwed. return; } _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0, framebufferManager_->GetMSAALevel()); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. return; } BindShaderBlendTex(); // This might cause copies so important to do before BindPipeline. - // If have a new render pass, dirty our dynamic state so it gets re-set. - // WARNING: We have to do this AFTER the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! - int curRenderStepId = renderManager->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); - lastRenderStepId_ = curRenderStepId; - } - renderManager->BindPipeline(pipeline->pipeline, pipeline->pipelineFlags, pipelineLayout_); if (pipeline != lastPipeline_) { if (lastPipeline_ && !(lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant())) { @@ -833,6 +828,11 @@ void DrawEngineVulkan::DoFlush() { } } else { PROFILE_THIS_SCOPE("soft"); + if (!decOptions_.applySkinInDecode) { + decOptions_.applySkinInDecode = true; + lastVType_ |= (1 << 26); + dec_ = GetVertexDecoder(lastVType_); + } DecodeVerts(decoded); bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { @@ -883,6 +883,10 @@ void DrawEngineVulkan::DoFlush() { swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_NOT_READY; if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); @@ -898,7 +902,7 @@ void DrawEngineVulkan::DoFlush() { textureCache_->ApplyTexture(); textureCache_->GetVulkanHandles(imageView, sampler); if (imageView == VK_NULL_HANDLE) - imageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::NULL_IMAGEVIEW); + imageView = (VkImageView)draw_->GetNativeObject(gstate_c.arrayTexture ? Draw::NativeObject::NULL_IMAGEVIEW_ARRAY : Draw::NativeObject::NULL_IMAGEVIEW); if (sampler == VK_NULL_HANDLE) sampler = nullSampler_; } @@ -906,28 +910,24 @@ void DrawEngineVulkan::DoFlush() { if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform + + VulkanVertexShader *vshader = nullptr; + VulkanFragmentShader *fshader = nullptr; + VulkanGeometryShader *gshader = nullptr; + + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0, framebufferManager_->GetMSAALevel()); if (!pipeline || !pipeline->pipeline) { // Already logged, let's bail out. decodedVerts_ = 0; numDrawCalls = 0; decodeCounter_ = 0; + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; return; } BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline. - // If have a new render pass, dirty our dynamic state so it gets re-set. - // WARNING: We have to do this AFTER the last possible place in DoFlush that can cause a renderpass switch - // like a shader blend blit or similar. But before we actually set the state! - int curRenderStepId = renderManager->GetCurrentStepId(); - if (lastRenderStepId_ != curRenderStepId) { - // Dirty everything that has dynamic state that will need re-recording. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); - lastRenderStepId_ = curRenderStepId; - } - renderManager->BindPipeline(pipeline->pipeline, pipeline->pipelineFlags, pipelineLayout_); if (pipeline != lastPipeline_) { if (lastPipeline_ && !lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant()) { @@ -973,7 +973,7 @@ void DrawEngineVulkan::DoFlush() { // If non-buffered though, it'll just do a plain clear. framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth); - if (gstate_c.Supports(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; @@ -981,6 +981,7 @@ void DrawEngineVulkan::DoFlush() { framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, result.color); } } + decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } gpuStats.numDrawCalls += numDrawCalls; @@ -1006,6 +1007,32 @@ void DrawEngineVulkan::DoFlush() { } void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { + if (!frame->frameDescSetUpdated) { + // Push frame global constants. + UB_Frame frameConstants{}; + FrameUpdateUniforms(&frameConstants, framebufferManager_->UseBufferedRendering()); + + VkDescriptorBufferInfo frameConstantsBufInfo; + frame->pushUBO->PushUBOData(frameConstants, &frameConstantsBufInfo); + + VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw_->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + + VkDescriptorSet frameDescSet = frame->descPool.Allocate(1, &frameDescSetLayout, "frame_desc_set"); + + VkWriteDescriptorSet descWrite{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descWrite.descriptorCount = 1; + descWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descWrite.dstBinding = 0; + descWrite.dstSet = frameDescSet; + descWrite.pBufferInfo = &frameConstantsBufInfo; + vkUpdateDescriptorSets(vulkan->GetDevice(), 1, &descWrite, 0, nullptr); + renderManager->BindDescriptorSet(0, frameDescSet, pipelineLayout_); + + frame->frameDescSetUpdated = true; + } + if ((dirtyUniforms_ & DIRTY_BASE_UNIFORMS) || baseBuf == VK_NULL_HANDLE) { baseUBOOffset = shaderManager_->PushBaseBuffer(frame->pushUBO, &baseBuf); dirtyUniforms_ &= ~DIRTY_BASE_UNIFORMS; diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index ebf50e33b5..afc61a25f4 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -43,6 +43,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/Vulkan/StateMappingVulkan.h" +#include "GPU/Vulkan/VulkanRenderManager.h" struct DecVtxFormat; struct UVScale; @@ -121,11 +122,25 @@ private: VkDescriptorBufferInfo bufInfo_[3]{}; }; +enum { + DRAW_BINDING_TEXTURE = 0, + DRAW_BINDING_2ND_TEXTURE = 1, + DRAW_BINDING_DEPAL_TEXTURE = 2, + DRAW_BINDING_DYNUBO_BASE = 3, + DRAW_BINDING_DYNUBO_LIGHT = 4, + DRAW_BINDING_DYNUBO_BONE = 5, + DRAW_BINDING_TESS_STORAGE_BUF = 6, + DRAW_BINDING_TESS_STORAGE_BUF_WU = 7, + DRAW_BINDING_TESS_STORAGE_BUF_WV = 8, + DRAW_BINDING_INPUT_ATTACHMENT = 9, + DRAW_BINDING_COUNT = 10, +}; + // Handles transform, lighting and drawing. class DrawEngineVulkan : public DrawEngineCommon { public: DrawEngineVulkan(Draw::DrawContext *draw); - virtual ~DrawEngineVulkan(); + ~DrawEngineVulkan(); // We reference feature flags, so this is called after construction. void InitDeviceObjects(); @@ -194,6 +209,8 @@ public: } private: + void Invalidate(InvalidationCallbackFlags flags); + struct FrameData; void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState); @@ -211,8 +228,10 @@ private: Draw::DrawContext *draw_; - // We use a single descriptor set layout for all PSP draws. + // We use a shared descriptor set layouts for all PSP draws. + // Descriptors created from descriptorSetLayout_ is rebound all the time at set 1. VkDescriptorSetLayout descriptorSetLayout_; + VkPipelineLayout pipelineLayout_; VulkanPipeline *lastPipeline_; VkDescriptorSet lastDs_ = VK_NULL_HANDLE; @@ -253,6 +272,8 @@ private: VulkanPushBuffer *pushVertex = nullptr; VulkanPushBuffer *pushIndex = nullptr; + bool frameDescSetUpdated = false; + // We do rolling allocation and reset instead of caching across frames. That we might do later. DenseHashMap descSets; @@ -290,6 +311,4 @@ private: // Hardware tessellation TessellationDataTransferVulkan *tessDataTransferVulkan; - - int lastRenderStepId_ = -1; }; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 64f69a861b..b3ad3c7689 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -52,7 +52,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw) { - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); drawEngine_.InitDeviceObjects(); VulkanContext *vulkan = (VulkanContext *)gfxCtx->GetAPIContext(); @@ -76,7 +76,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_); framebufferManagerVulkan_->SetDrawEngine(&drawEngine_); framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_); - framebufferManagerVulkan_->Init(); + framebufferManagerVulkan_->Init(msaaLevel_); textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_); textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_); textureCacheVulkan_->SetDrawEngine(&drawEngine_); @@ -121,7 +121,7 @@ void GPU_Vulkan::CancelReady() { void GPU_Vulkan::LoadCache(const Path &filename) { if (!g_Config.bShaderCache) { - INFO_LOG(G3D, "Shader cache disabled. Not loading."); + WARN_LOG(G3D, "Shader cache disabled. Not loading."); return; } @@ -135,11 +135,15 @@ void GPU_Vulkan::LoadCache(const Path &filename) { // It's when recreating the pipelines that the pipeline cache is useful - in the ideal case, // it can just memcpy the finished shader binaries out of the pipeline cache file. bool result = shaderManagerVulkan_->LoadCache(f); + if (!result) { + WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache."); + } if (result) { - // WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true. - result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout()); + // WARNING: See comment in LoadPipelineCache if you are tempted to flip the second parameter to true. + result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout(), msaaLevel_); } fclose(f); + if (!result) { WARN_LOG(G3D, "Incompatible Vulkan pipeline cache - rebuilding."); // Bad cache file for this GPU/Driver/etc. Delete it. @@ -166,7 +170,7 @@ void GPU_Vulkan::SaveCache(const Path &filename) { return; shaderManagerVulkan_->SaveCache(f); // WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true. - pipelineManager_->SaveCache(f, false, shaderManagerVulkan_, draw_); + pipelineManager_->SavePipelineCache(f, false, shaderManagerVulkan_, draw_); INFO_LOG(G3D, "Saved Vulkan pipeline cache"); fclose(f); } @@ -190,11 +194,11 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { switch (vulkan->GetPhysicalDeviceProperties().properties.vendorID) { case VULKAN_VENDOR_AMD: // Accurate depth is required on AMD (due to reverse-Z driver bug) so we ignore the compat flag to disable it on those. See #9545 - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; break; case VULKAN_VENDOR_QUALCOMM: // Accurate depth is required on Adreno too (seems to also have a reverse-Z driver bug). - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; break; case VULKAN_VENDOR_ARM: { @@ -206,40 +210,40 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { || VK_VERSION_MAJOR(vulkan->GetPhysicalDeviceProperties().properties.driverVersion) < 14; if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || driverTooOld) { - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; + } else { + features &= ~GPU_USE_ACCURATE_DEPTH; } break; } default: if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) { - features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_USE_ACCURATE_DEPTH; + } else { + features &= ~GPU_USE_ACCURATE_DEPTH; } break; } // Might enable this later - in the first round we are mostly looking at depth/stencil/discard. // if (!g_Config.bEnableVendorBugChecks) - // features |= GPU_SUPPORTS_ACCURATE_DEPTH; + // features |= GPU_USE_ACCURATE_DEPTH; // Mandatory features on Vulkan, which may be checked in "centralized" code - features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - features |= GPU_SUPPORTS_INSTANCE_RENDERING; - features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; - features |= GPU_SUPPORTS_TEXTURE_FLOAT; - - auto &enabledFeatures = vulkan->GetDeviceFeatures().enabled; - if (enabledFeatures.depthClamp) { - features |= GPU_SUPPORTS_DEPTH_CLAMP; - } + features |= GPU_USE_TEXTURE_LOD_CONTROL; + features |= GPU_USE_INSTANCE_RENDERING; + features |= GPU_USE_VERTEX_TEXTURE_FETCH; + features |= GPU_USE_TEXTURE_FLOAT; // Fall back to geometry shader culling if we can't do vertex range culling. - if (enabledFeatures.geometryShader) { + // Checking accurate depth here because the old depth path is uncommon and not well tested for this. + if (draw_->GetDeviceCaps().geometryShaderSupported && (features & GPU_USE_ACCURATE_DEPTH) != 0) { const bool useGeometry = g_Config.bUseGeometryShader && !draw_->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN); const bool vertexSupported = draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported; - if (useGeometry && (!vertexSupported || (features & GPU_SUPPORTS_VS_RANGE_CULLING) == 0)) { + if (useGeometry && (!vertexSupported || (features & GPU_USE_VS_RANGE_CULLING) == 0)) { // Switch to culling via the geometry shader if not fully supported in vertex. - features |= GPU_SUPPORTS_GS_CULLING; - features &= ~GPU_SUPPORTS_VS_RANGE_CULLING; + features |= GPU_USE_GS_CULLING; + features &= ~GPU_USE_VS_RANGE_CULLING; } } @@ -252,39 +256,36 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { // if it's not available, for simplicity. uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::B5G6R5_UNORM_PACK16); if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) { - features |= GPU_SUPPORTS_16BIT_FORMATS; + features |= GPU_USE_16BIT_FORMATS; } else { INFO_LOG(G3D, "Deficient texture format support: 4444: %d 1555: %d 565: %d", fmt4444, fmt1555, fmt565); } - if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } - else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } - else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; + if (g_Config.bStereoRendering && draw_->GetDeviceCaps().multiViewSupported) { + features |= GPU_USE_SINGLE_PASS_STEREO; + features |= GPU_USE_SIMPLE_STEREO_PERSPECTIVE; + + features &= ~GPU_USE_FRAMEBUFFER_FETCH; // Need to figure out if this can be supported with multiview rendering + if (features & GPU_USE_GS_CULLING) { + // Many devices that support stereo and GS don't support GS during stereo. + features &= ~GPU_USE_GS_CULLING; + features |= GPU_USE_VS_RANGE_CULLING; + } } - return features; + // We need to turn off framebuffer fetch through input attachments if MSAA is on for now. + // This is fixable, just needs some shader generator work (subpassInputMS). + if (msaaLevel_ != 0) { + features &= ~GPU_USE_FRAMEBUFFER_FETCH; + } + + return CheckGPUFeaturesLate(features); } void GPU_Vulkan::BeginHostFrame() { + GPUCommon::BeginHostFrame(); + drawEngine_.BeginFrame(); - UpdateCmdInfo(); - - if (resized_) { - gstate_c.featureFlags = CheckGPUFeatures(); - // In case the GPU changed. - BuildReportingInfo(); - framebufferManager_->Resized(); - drawEngine_.Resized(); - textureCache_->NotifyConfigChanged(); - resized_ = false; - } - textureCacheVulkan_->StartFrame(); VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); @@ -318,24 +319,21 @@ void GPU_Vulkan::EndHostFrame() { drawEngine_.EndFrame(); textureCacheVulkan_->EndFrame(); - draw_->InvalidateCachedState(); + GPUCommon::EndHostFrame(); } // Needs to be called on GPU thread, not reporting thread. void GPU_Vulkan::BuildReportingInfo() { VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); const auto &props = vulkan->GetPhysicalDeviceProperties().properties; - const auto &features = vulkan->GetDeviceFeatures().available; + const auto &available = vulkan->GetDeviceFeatures().available; -#define CHECK_BOOL_FEATURE(n) do { if (features.n) { featureNames += ", " #n; } } while (false) +#define CHECK_BOOL_FEATURE(n) do { if (available.standard.n) { featureNames += ", " #n; } } while (false) +#define CHECK_BOOL_FEATURE_MULTIVIEW(n) do { if (available.multiview.n) { featureNames += ", " #n; } } while (false) std::string featureNames = ""; - CHECK_BOOL_FEATURE(robustBufferAccess); CHECK_BOOL_FEATURE(fullDrawIndexUint32); - CHECK_BOOL_FEATURE(imageCubeArray); - CHECK_BOOL_FEATURE(independentBlend); CHECK_BOOL_FEATURE(geometryShader); - CHECK_BOOL_FEATURE(tessellationShader); CHECK_BOOL_FEATURE(sampleRateShading); CHECK_BOOL_FEATURE(dualSrcBlend); CHECK_BOOL_FEATURE(logicOp); @@ -343,46 +341,23 @@ void GPU_Vulkan::BuildReportingInfo() { CHECK_BOOL_FEATURE(drawIndirectFirstInstance); CHECK_BOOL_FEATURE(depthClamp); CHECK_BOOL_FEATURE(depthBiasClamp); - CHECK_BOOL_FEATURE(fillModeNonSolid); CHECK_BOOL_FEATURE(depthBounds); - CHECK_BOOL_FEATURE(alphaToOne); - CHECK_BOOL_FEATURE(multiViewport); CHECK_BOOL_FEATURE(samplerAnisotropy); CHECK_BOOL_FEATURE(textureCompressionETC2); CHECK_BOOL_FEATURE(textureCompressionASTC_LDR); CHECK_BOOL_FEATURE(textureCompressionBC); CHECK_BOOL_FEATURE(occlusionQueryPrecise); CHECK_BOOL_FEATURE(pipelineStatisticsQuery); - CHECK_BOOL_FEATURE(vertexPipelineStoresAndAtomics); CHECK_BOOL_FEATURE(fragmentStoresAndAtomics); CHECK_BOOL_FEATURE(shaderTessellationAndGeometryPointSize); - CHECK_BOOL_FEATURE(shaderImageGatherExtended); - CHECK_BOOL_FEATURE(shaderStorageImageExtendedFormats); CHECK_BOOL_FEATURE(shaderStorageImageMultisample); - CHECK_BOOL_FEATURE(shaderStorageImageReadWithoutFormat); - CHECK_BOOL_FEATURE(shaderStorageImageWriteWithoutFormat); - CHECK_BOOL_FEATURE(shaderUniformBufferArrayDynamicIndexing); CHECK_BOOL_FEATURE(shaderSampledImageArrayDynamicIndexing); - CHECK_BOOL_FEATURE(shaderStorageBufferArrayDynamicIndexing); - CHECK_BOOL_FEATURE(shaderStorageImageArrayDynamicIndexing); CHECK_BOOL_FEATURE(shaderClipDistance); CHECK_BOOL_FEATURE(shaderCullDistance); - CHECK_BOOL_FEATURE(shaderFloat64); CHECK_BOOL_FEATURE(shaderInt64); CHECK_BOOL_FEATURE(shaderInt16); - CHECK_BOOL_FEATURE(shaderResourceResidency); - CHECK_BOOL_FEATURE(shaderResourceMinLod); - CHECK_BOOL_FEATURE(sparseBinding); - CHECK_BOOL_FEATURE(sparseResidencyBuffer); - CHECK_BOOL_FEATURE(sparseResidencyImage2D); - CHECK_BOOL_FEATURE(sparseResidencyImage3D); - CHECK_BOOL_FEATURE(sparseResidency2Samples); - CHECK_BOOL_FEATURE(sparseResidency4Samples); - CHECK_BOOL_FEATURE(sparseResidency8Samples); - CHECK_BOOL_FEATURE(sparseResidency16Samples); - CHECK_BOOL_FEATURE(sparseResidencyAliased); - CHECK_BOOL_FEATURE(variableMultisampleRate); - CHECK_BOOL_FEATURE(inheritedQueries); + CHECK_BOOL_FEATURE_MULTIVIEW(multiview); + CHECK_BOOL_FEATURE_MULTIVIEW(multiviewGeometryShader); #undef CHECK_BOOL_FEATURE @@ -494,6 +469,14 @@ void GPU_Vulkan::DestroyDeviceObjects() { } } +void GPU_Vulkan::CheckRenderResized() { + if (renderResized_) { + GPUCommon::CheckRenderResized(); + pipelineManager_->InvalidateMSAAPipelines(); + framebufferManager_->ReleasePipelines(); + } +} + void GPU_Vulkan::DeviceLost() { CancelReady(); while (!IsReady()) { @@ -515,7 +498,7 @@ void GPU_Vulkan::DeviceRestore() { GPUCommon::DeviceRestore(); InitDeviceObjects(); - gstate_c.featureFlags = CheckGPUFeatures(); + gstate_c.SetUseFlags(CheckGPUFeatures()); BuildReportingInfo(); UpdateCmdInfo(); @@ -549,14 +532,6 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { ); } -void GPU_Vulkan::ClearCacheNextFrame() { - textureCacheVulkan_->ClearNextFrame(); -} - -void GPU_Vulkan::ClearShaderCache() { - // TODO -} - void GPU_Vulkan::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 3fbd329aae..eefaa23b3c 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -51,14 +51,11 @@ public: void ExecuteOp(u32 op, u32 diff) override; void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceRestore() override; void DoState(PointerWrap &p) override; - void ClearShaderCache() override; - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; @@ -71,13 +68,11 @@ public: protected: void FinishDeferred() override; + void CheckRenderResized() override; private: - void Flush() { - drawEngine_.Flush(); - } void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); + void BuildReportingInfo() override; void InitClear() override; void CopyDisplayToOutput(bool reallyDirty) override; void Reinitialize() override; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 3d7745b452..e8ae8d9db6 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -8,10 +8,12 @@ #include "Common/Log.h" #include "Common/StringUtils.h" #include "Common/GPU/Vulkan/VulkanContext.h" +#include "Core/Config.h" #include "GPU/Vulkan/VulkanUtil.h" #include "GPU/Vulkan/PipelineManagerVulkan.h" #include "GPU/Vulkan/ShaderManagerVulkan.h" #include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/ShaderId.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/Vulkan/VulkanRenderManager.h" #include "Common/GPU/Vulkan/VulkanQueueRunner.h" @@ -47,6 +49,12 @@ void PipelineManagerVulkan::Clear() { pipelines_.Clear(); } +void PipelineManagerVulkan::InvalidateMSAAPipelines() { + pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) { + value->pipeline->DestroyVariants(vulkan_, true); + }); +} + void PipelineManagerVulkan::DeviceLost() { Clear(); if (pipelineCache_ != VK_NULL_HANDLE) @@ -170,10 +178,11 @@ static std::string CutFromMain(std::string str) { } static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache, - VkPipelineLayout layout, PipelineFlags pipelineFlags, const VulkanPipelineRasterStateKey &key, + VkPipelineLayout layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) { VulkanPipeline *vulkanPipeline = new VulkanPipeline(); - VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc; + vulkanPipeline->desc = new VKRGraphicsPipelineDesc(); + VKRGraphicsPipelineDesc *desc = vulkanPipeline->desc; desc->pipelineCache = pipelineCache; PROFILE_THIS_SCOPE("pipelinebuild"); @@ -248,20 +257,18 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, rs.polygonMode = VK_POLYGON_MODE_FILL; rs.depthClampEnable = key.depthClampEnable; - VkPipelineMultisampleStateCreateInfo &ms = desc->ms; - ms.pSampleMask = nullptr; - ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - desc->fragmentShader = fs->GetModule(); desc->vertexShader = vs->GetModule(); desc->geometryShader = gs ? gs->GetModule() : nullptr; + desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE); + desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE); + if (gs) { + desc->geometryShaderSource = gs->GetShaderString(SHADER_STRING_SOURCE_CODE); + } + + desc->topology = (VkPrimitiveTopology)key.topology; - VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly; - inputAssembly.flags = 0; - inputAssembly.topology = (VkPrimitiveTopology)key.topology; - inputAssembly.primitiveRestartEnable = false; int vertexStride = 0; - VkVertexInputAttributeDescription *attrs = &desc->attrs[0]; int attributeCount; @@ -296,7 +303,12 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, desc->pipelineLayout = layout; - VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, "game"); + std::string tag = "game"; +#ifdef _DEBUG + tag = FragmentShaderDesc(fs->GetID()) + " VS " + VertexShaderDesc(vs->GetID()); +#endif + + VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, sampleCount, tag.c_str()); vulkanPipeline->pipeline = pipeline; if (useBlendConstant) { @@ -312,7 +324,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, return vulkanPipeline; } -VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) { +VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel) { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); @@ -336,9 +348,17 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * if (fs->Flags() & FragmentShaderFlags::INPUT_ATTACHMENT) { pipelineFlags |= PipelineFlags::USES_INPUT_ATTACHMENT; } + if (fs->Flags() & FragmentShaderFlags::USES_DISCARD) { + pipelineFlags |= PipelineFlags::USES_DISCARD; + } + if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) { + pipelineFlags |= PipelineFlags::USES_MULTIVIEW; + } + + VkSampleCountFlagBits sampleCount = MultiSampleLevelToFlagBits(multiSampleLevel); VulkanPipeline *pipeline = CreateVulkanPipeline( - renderManager, pipelineCache_, layout, pipelineFlags, + renderManager, pipelineCache_, layout, pipelineFlags, sampleCount, rasterKey, decFmt, vs, fs, gs, useHwTransform, variantBitmask); pipelines_.Insert(key, pipeline); @@ -350,7 +370,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * } } -std::vector PipelineManagerVulkan::DebugGetObjectIDs(DebugShaderType type) { +std::vector PipelineManagerVulkan::DebugGetObjectIDs(DebugShaderType type) const { std::vector ids; switch (type) { case SHADER_TYPE_PIPELINE: @@ -455,13 +475,14 @@ std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugSha VulkanPipelineKey pipelineKey; pipelineKey.FromString(id); - VulkanPipeline *iter = pipelines_.Get(pipelineKey); - if (!iter) { - return ""; + VulkanPipeline *pipeline = pipelines_.Get(pipelineKey); + if (!pipeline) { + return "N/A (missing)"; } + u32 variants = pipeline->GetVariantsBitmask(); - std::string str = pipelineKey.GetDescription(stringType); - return StringFromFormat("%p: %s", iter, str.c_str()); + std::string keyDescription = pipelineKey.GetDescription(stringType); + return StringFromFormat("%s. v: %08x", keyDescription.c_str(), variants); } std::string VulkanPipelineKey::GetDescription(DebugShaderStringType stringType) const { @@ -557,7 +578,7 @@ struct StoredVulkanPipelineKey { // If you're looking for how to invalidate the cache, it's done in ShaderManagerVulkan, look for CACHE_VERSION and increment it. // (Header of the same file this is stored in). -void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) { +void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); @@ -646,12 +667,15 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha } } -bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) { +bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, int multiSampleLevel) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); + cancelCache_ = false; + uint32_t size = 0; if (loadRawPipelineCache) { + NOTICE_LOG(G3D, "WARNING: Using the badly tested raw pipeline cache path!!!!"); // WARNING: Do not use this path until after reading and implementing https://zeux.io/2019/07/17/serializing-pipeline-cache/ ! bool success = fread(&size, sizeof(size), 1, file) == 1; if (!size || !success) { @@ -687,12 +711,14 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha } else { vkMergePipelineCaches(vulkan_->GetDevice(), pipelineCache_, 1, &cache); } - NOTICE_LOG(G3D, "Loaded Vulkan pipeline cache (%d bytes).", (int)size); + NOTICE_LOG(G3D, "Loaded Vulkan binary pipeline cache (%d bytes).", (int)size); + // Note that after loading the cache, it's still a good idea to pre-create the various pipelines. } else { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); if (res != VK_SUCCESS) { + WARN_LOG(G3D, "vkCreatePipelineCache failed (%08x), highly unexpected", (u32)res); return false; } } @@ -701,8 +727,9 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha // Read the number of pipelines. bool failed = fread(&size, sizeof(size), 1, file) != 1; - NOTICE_LOG(G3D, "Creating %d pipelines...", size); + NOTICE_LOG(G3D, "Creating %d pipelines from cache (%dx MSAA)...", size, (1 << multiSampleLevel)); int pipelineCreateFailCount = 0; + int shaderFailCount = 0; for (uint32_t i = 0; i < size; i++) { if (failed || cancelCache_) { break; @@ -710,21 +737,33 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha StoredVulkanPipelineKey key; failed = failed || fread(&key, sizeof(key), 1, file) != 1; if (failed) { - ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file"); - continue; + ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file, stopping."); + break; } VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID); VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID); VulkanGeometryShader *gs = shaderManager->GetGeometryShaderFromID(key.gShaderID); if (!vs || !fs || (!gs && key.gShaderID.Bit(GS_BIT_ENABLED))) { - failed = true; - ERROR_LOG(G3D, "Failed to find vs or fs in of pipeline %d in cache", (int)i); + // We just ignore this one, it'll get created later if needed. + // Probably some useFlags mismatch. + WARN_LOG(G3D, "Failed to find vs or fs in pipeline %d in cache, skipping pipeline", (int)i); continue; } + // Avoid creating multisampled shaders if it's not enabled, as that results in an invalid combination. + u32 variantsToBuild = key.variants; + if (multiSampleLevel == 0) { + for (u32 i = 0; i < (int)RenderPassType::TYPE_COUNT; i++) { + if (RenderPassTypeHasMultisample((RenderPassType)i)) { + variantsToBuild &= ~(1 << i); + } + } + } + DecVtxFormat fmt; fmt.InitializeFromID(key.vtxFmtId); - VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, key.variants); + VulkanPipeline *pipeline = GetOrCreatePipeline( + rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, variantsToBuild, multiSampleLevel); if (!pipeline) { pipelineCreateFailCount += 1; } @@ -733,6 +772,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha rm->NudgeCompilerThread(); NOTICE_LOG(G3D, "Recreated Vulkan pipeline cache (%d pipelines, %d failed).", (int)size, pipelineCreateFailCount); + // We just ignore any failures. return true; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 32e45c3faf..cb1cc4fb88 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -54,14 +54,19 @@ struct VulkanPipelineKey { // Simply wraps a Vulkan pipeline, providing some metadata. struct VulkanPipeline { + ~VulkanPipeline() { + desc->Release(); + } + VKRGraphicsPipeline *pipeline; - VKRGraphicsPipelineDesc desc; + VKRGraphicsPipelineDesc *desc; PipelineFlags pipelineFlags; // PipelineFlags enum above. bool UsesBlendConstant() const { return (pipelineFlags & PipelineFlags::USES_BLEND_CONSTANT) != 0; } bool UsesDepthStencil() const { return (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) != 0; } bool UsesInputAttachment() const { return (pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) != 0; } bool UsesGeometryShader() const { return (pipelineFlags & PipelineFlags::USES_GEOMETRY_SHADER) != 0; } + bool UsesDiscard() const { return (pipelineFlags & PipelineFlags::USES_DISCARD) != 0; } u32 GetVariantsBitmask() const; }; @@ -79,7 +84,7 @@ public: ~PipelineManagerVulkan(); // variantMask is only used when loading pipelines from cache. - VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask); + VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask, int multiSampleLevel); int GetNumPipelines() const { return (int)pipelines_.size(); } void Clear(); @@ -87,12 +92,14 @@ public: void DeviceLost(); void DeviceRestore(VulkanContext *vulkan); + void InvalidateMSAAPipelines(); + std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType); - std::vector DebugGetObjectIDs(DebugShaderType type); + std::vector DebugGetObjectIDs(DebugShaderType type) const; // Saves data for faster creation next time. - void SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext); - bool LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout); + void SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext); + bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, int multiSampleLevel); void CancelCache(); private: diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index c7724da670..bec74abcff 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -25,6 +25,7 @@ #include "Common/Profiler/Profiler.h" #include "Common/GPU/thin3d.h" #include "Common/Data/Encoding/Utf8.h" +#include "Common/TimeUtil.h" #include "Common/StringUtils.h" #include "Common/GPU/Vulkan/VulkanContext.h" @@ -81,6 +82,7 @@ static Promise *CompileShaderModuleAsync(VulkanContext *vulkan, case VK_SHADER_STAGE_FRAGMENT_BIT: createTag = "game_fragment"; break; case VK_SHADER_STAGE_GEOMETRY_BIT: createTag = "game_geometry"; break; case VK_SHADER_STAGE_COMPUTE_BIT: createTag = "game_compute"; break; + default: break; } } @@ -91,11 +93,10 @@ static Promise *CompileShaderModuleAsync(VulkanContext *vulkan, if (tag) delete tag; } - return shaderModule; }; -#ifdef _DEBUG +#if defined(_DEBUG) // Don't parallelize in debug mode, pathological behavior due to mutex locks in allocator which is HEAVILY used by glslang. return Promise::AlreadyDone(compile()); #else @@ -119,7 +120,10 @@ VulkanFragmentShader::~VulkanFragmentShader() { if (module_) { VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } @@ -134,8 +138,8 @@ std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) co } } -VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform) - : vulkan_(vulkan), useHWTransform_(useHWTransform), id_(id) { +VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, VertexShaderFlags flags, const char *code, bool useHWTransform) + : vulkan_(vulkan), useHWTransform_(useHWTransform), flags_(flags), id_(id) { source_ = code; module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str(), new std::string(VertexShaderDesc(id))); if (!module_) { @@ -149,7 +153,10 @@ VulkanVertexShader::~VulkanVertexShader() { if (module_) { VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } @@ -179,7 +186,10 @@ VulkanGeometryShader::~VulkanGeometryShader() { if (module_) { VkShaderModule shaderModule = module_->BlockUntilReady(); vulkan_->Delete().QueueDeleteShaderModule(shaderModule); - delete module_; + vulkan_->Delete().QueueCallback([](void *m) { + auto module = (Promise *)m; + delete module; + }, module_); } } @@ -279,11 +289,11 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) { return dirty; } -void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { +void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) { VShaderID VSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode); } else { VSID = lastVSID_; } @@ -330,10 +340,11 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader std::string genErrorString; uint64_t uniformMask = 0; // Not used uint32_t attributeMask = 0; // Not used - bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString); + VertexShaderFlags flags{}; + bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString); _assert_msg_(success, "VS gen error: %s", genErrorString.c_str()); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); - vs = new VulkanVertexShader(vulkan, VSID, codeBuffer_, useHWTransform); + vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform); vsCache_.Insert(VSID, vs); } @@ -342,7 +353,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader // Fragment shader not in cache. Let's compile it. std::string genErrorString; uint64_t uniformMask = 0; // Not used - FragmentShaderFlags flags; + FragmentShaderFlags flags{}; bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString); _assert_msg_(success, "FS gen error: %s", genErrorString.c_str()); _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); @@ -482,11 +493,11 @@ VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 29 +#define CACHE_VERSION 32 struct VulkanCacheHeader { uint32_t magic; uint32_t version; - uint32_t featureFlags; + uint32_t useFlags; uint32_t reserved; int numVertexShaders; int numFragmentShaders; @@ -496,29 +507,43 @@ struct VulkanCacheHeader { bool ShaderManagerVulkan::LoadCache(FILE *f) { VulkanCacheHeader header{}; bool success = fread(&header, sizeof(header), 1, f) == 1; - if (!success || header.magic != CACHE_HEADER_MAGIC) + if (!success || header.magic != CACHE_HEADER_MAGIC) { + WARN_LOG(G3D, "Shader cache magic mismatch"); return false; - if (header.version != CACHE_VERSION) - return false; - if (header.featureFlags != gstate_c.featureFlags) + } + if (header.version != CACHE_VERSION) { + WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); return false; + } + + if (header.useFlags != gstate_c.GetUseFlags()) { + // This can simply be a result of sawExactEqualDepth_ having been flipped to true in the previous run. + // Let's just keep going. + WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags()); + } + + int failCount = 0; VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); for (int i = 0; i < header.numVertexShaders; i++) { VShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated"); - break; + ERROR_LOG(G3D, "Vulkan shader cache truncated (in VertexShaders)"); + return false; } bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); std::string genErrorString; uint32_t attributeMask = 0; uint64_t uniformMask = 0; - if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString)) { - return false; + VertexShaderFlags flags; + if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) { + WARN_LOG(G3D, "Failed to generate vertex shader during cache load"); + // We just ignore this one and carry on. + failCount++; + continue; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); - VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, codeBuffer_, useHWTransform); + VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, flags, codeBuffer_, useHWTransform); vsCache_.Insert(id, vs); } uint32_t vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID; @@ -526,14 +551,17 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numFragmentShaders; i++) { FShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated"); - break; + ERROR_LOG(G3D, "Vulkan shader cache truncated (in FragmentShaders)"); + return false; } std::string genErrorString; uint64_t uniformMask = 0; FragmentShaderFlags flags; if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString)) { - return false; + WARN_LOG(G3D, "Failed to generate fragment shader during cache load"); + // We just ignore this one and carry on. + failCount++; + continue; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan, id, flags, codeBuffer_); @@ -543,19 +571,22 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numGeometryShaders; i++) { GShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated"); - break; + ERROR_LOG(G3D, "Vulkan shader cache truncated (in GeometryShaders)"); + return false; } std::string genErrorString; if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) { - return false; + WARN_LOG(G3D, "Failed to generate geometry shader during cache load"); + // We just ignore this one and carry on. + failCount++; + continue; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_)); VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_); gsCache_.Insert(id, gs); } - NOTICE_LOG(G3D, "Loaded %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders); + NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders (failed %d)", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders, failCount); return true; } @@ -563,7 +594,7 @@ void ShaderManagerVulkan::SaveCache(FILE *f) { VulkanCacheHeader header{}; header.magic = CACHE_HEADER_MAGIC; header.version = CACHE_VERSION; - header.featureFlags = gstate_c.featureFlags; + header.useFlags = gstate_c.GetUseFlags(); header.reserved = 0; header.numVertexShaders = (int)vsCache_.size(); header.numFragmentShaders = (int)fsCache_.size(); diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index 4c89f91ef5..8e6ce2636a 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -61,13 +61,14 @@ protected: class VulkanVertexShader { public: - VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform); + VulkanVertexShader(VulkanContext *vulkan, VShaderID id, VertexShaderFlags flags, const char *code, bool useHWTransform); ~VulkanVertexShader(); const std::string &source() const { return source_; } bool Failed() const { return failed_; } - bool UseHWTransform() const { return useHWTransform_; } + bool UseHWTransform() const { return useHWTransform_; } // TODO: Roll into flags + VertexShaderFlags Flags() const { return flags_; } std::string GetShaderString(DebugShaderStringType type) const; Promise *GetModule() { return module_; } @@ -81,6 +82,7 @@ protected: bool failed_ = false; bool useHWTransform_; VShaderID id_; + VertexShaderFlags flags_; }; class VulkanGeometryShader { @@ -113,7 +115,7 @@ public: void DeviceLost(); void DeviceRestore(Draw::DrawContext *draw); - void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); + void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode); void ClearShaders(); void DirtyShader(); void DirtyLastShader() override; diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 4a81988a7f..90d57abd9c 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -209,10 +209,11 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag if ((gstate.pmskc & 0x00FFFFFF) == 0x00FFFFFF && g_Config.bVendorBugChecksEnabled && draw_->GetBugs().Has(Draw::Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST)) { key.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; if (!key.blendEnable) { + bool writeAlpha = maskState.channelMask & 8; key.blendEnable = true; key.blendOpAlpha = VK_BLEND_OP_ADD; - key.srcAlpha = VK_BLEND_FACTOR_ZERO; - key.destAlpha = VK_BLEND_FACTOR_ONE; + key.srcAlpha = writeAlpha ? VK_BLEND_FACTOR_ONE : VK_BLEND_FACTOR_ZERO; + key.destAlpha = writeAlpha ? VK_BLEND_FACTOR_ZERO : VK_BLEND_FACTOR_ONE; } key.blendOpColor = VK_BLEND_OP_ADD; key.srcColor = VK_BLEND_FACTOR_ZERO; @@ -232,7 +233,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { // TODO: Still has a bug where we clamp to depth range if one is not the full range. // But the alternate is not clamping in either direction... - key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Use(GPU_USE_DEPTH_CLAMP); } else { // We just want to clip in this case, the clamp would be clipped anyway. key.depthClampEnable = false; @@ -274,10 +275,11 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag } } else { // Depth Test - if (gstate.isDepthTestEnabled()) { + if (!IsDepthTestEffectivelyDisabled()) { key.depthTestEnable = true; key.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; key.depthWriteEnable = gstate.isDepthWriteEnabled(); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { key.depthTestEnable = false; key.depthWriteEnable = false; @@ -365,7 +367,8 @@ void DrawEngineVulkan::BindShaderBlendTex() { // Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? if (!gstate.isModeClear()) { if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) { - bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY); + VirtualFramebuffer *curRenderVfb = framebufferManager_->GetCurrentRenderVFB(); + bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, curRenderVfb, BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS); _dbg_assert_(bindResult); boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE1_IMAGEVIEW); boundSecondaryIsInputAttachment_ = false; @@ -376,10 +379,11 @@ void DrawEngineVulkan::BindShaderBlendTex() { dirtyRequiresRecheck_ |= DIRTY_BLEND_STATE; } else if (fboTexBindState_ == FBO_TEX_READ_FRAMEBUFFER) { draw_->BindCurrentFramebufferForColorInput(); - boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW); + boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT, (void *)0); boundSecondaryIsInputAttachment_ = true; fboTexBindState_ = FBO_TEX_NONE; } else { + boundSecondaryIsInputAttachment_ = false; boundSecondary_ = VK_NULL_HANDLE; } } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 1a910bc5a1..3205453c21 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -65,9 +65,9 @@ const char *uploadShader = R"( // hardware vendors. layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; -uniform layout(binding = 0, rgba8) writeonly image2D img; +uniform layout(set = 1, binding = 0, rgba8) writeonly image2D img; -layout(std430, binding = 1) buffer Buf { +layout(std430, set = 1, binding = 1) buffer Buf { uint data[]; } buf; @@ -251,7 +251,7 @@ void TextureCacheVulkan::DeviceRestore(Draw::DrawContext *draw) { CompileScalingShader(); - computeShaderManager_.DeviceRestore(vulkan); + computeShaderManager_.DeviceRestore(draw); } void TextureCacheVulkan::NotifyConfigChanged() { @@ -404,8 +404,6 @@ void TextureCacheVulkan::BindTexture(TexCacheEntry *entry) { return; } - entry->vkTex->Touch(); - int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel; SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry); curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey); @@ -482,7 +480,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); delete entry->vkTex; - entry->vkTex = new VulkanTexture(vulkan); + + char texName[64]{}; + snprintf(texName, sizeof(texName), "tex_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat())); + entry->vkTex = new VulkanTexture(vulkan, texName); VulkanTexture *image = entry->vkTex; const VkComponentMapping *mapping; @@ -513,10 +514,6 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { actualFmt = VULKAN_8888_FORMAT; } - char texName[128]{}; - snprintf(texName, sizeof(texName), "tex_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat())); - image->SetTag(texName); - bool allocSuccess = image->CreateDirect(cmdInit, plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, imageLayout, usage, mapping); if (!allocSuccess && !lowMemoryMode_) { WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); @@ -591,7 +588,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } else { data = drawEngine_->GetPushBufferForTextureData()->PushAligned(sz, &bufferOffset, &texBuf, pushAlignment); } - LoadTextureLevel(*entry, (uint8_t *)data, lstride, srcLevel, lfactor, actualFmt); + LoadVulkanTextureLevel(*entry, (uint8_t *)data, lstride, srcLevel, lfactor, actualFmt); if (plan.saveTexture) bufferOffset = drawEngine_->GetPushBufferForTextureData()->PushAligned(&saveData[0], sz, pushAlignment, &texBuf); }; @@ -626,7 +623,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, "Compute Upload: %dx%d->%dx%d", mipUnscaledWidth, mipUnscaledHeight, mipWidth, mipHeight); vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipeline(uploadCS_)); - vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 0, 1, &descSet, 0, nullptr); + vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 1, 1, &descSet, 0, nullptr); vkCmdPushConstants(cmdInit, computeShaderManager_.GetPipelineLayout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(params), ¶ms); vkCmdDispatch(cmdInit, (mipUnscaledWidth + 7) / 8, (mipUnscaledHeight + 7) / 8, 1); VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); @@ -685,7 +682,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS)) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS)) { return VK_FORMAT_R8G8B8A8_UNORM; } switch (format) { @@ -709,7 +706,7 @@ VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteForm } } -void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt) { +void TextureCacheVulkan::LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt) { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); @@ -726,7 +723,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt int decPitch; TexDecodeFlags texDecFlags{}; - if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { + if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { texDecFlags |= TexDecodeFlags::EXPAND32; } if (entry.status & TexCacheEntry::STATUS_CLUT_GPU) { @@ -846,6 +843,6 @@ std::string TextureCacheVulkan::DebugGetSamplerString(std::string id, DebugShade } void *TextureCacheVulkan::GetNativeTextureView(const TexCacheEntry *entry) { - VkImageView view = entry->vkTex->GetImageView(); + VkImageView view = entry->vkTex->GetImageArrayView(); return (void *)view; } diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index f83595dc46..2c16d02a03 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -100,7 +100,7 @@ protected: void *GetNativeTextureView(const TexCacheEntry *entry) override; private: - void LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt); + void LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt); VkFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index fb82f9a474..d878bff579 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -56,7 +56,7 @@ VulkanComputeShaderManager::VulkanComputeShaderManager(VulkanContext *vulkan) : } VulkanComputeShaderManager::~VulkanComputeShaderManager() {} -void VulkanComputeShaderManager::InitDeviceObjects() { +void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); _assert_(VK_SUCCESS == res); @@ -106,8 +106,10 @@ void VulkanComputeShaderManager::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = &push; pl.pushConstantRangeCount = 1; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + VkDescriptorSetLayout setLayouts[2] = { frameDescSetLayout, descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(setLayouts); + pl.pSetLayouts = setLayouts; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _assert_(VK_SUCCESS == res); @@ -136,10 +138,10 @@ void VulkanComputeShaderManager::DestroyDeviceObjects() { VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkBuffer buffer2, VkDeviceSize offset2, VkDeviceSize range2) { int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; - VkDescriptorSet desc = frameData.descPool.Allocate(1, &descriptorSetLayout_); + VkDescriptorSet desc = frameData.descPool.Allocate(1, &descriptorSetLayout_, "compute_descset"); _assert_(desc != VK_NULL_HANDLE); - VkWriteDescriptorSet writes[2]{}; + VkWriteDescriptorSet writes[3]{}; int n = 0; VkDescriptorImageInfo imageInfo = {}; VkDescriptorBufferInfo bufferInfo[2] = {}; diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index b31fdb75f9..8663d3ce1e 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -25,6 +25,7 @@ #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/thin3d.h" extern const VkComponentMapping VULKAN_4444_SWIZZLE; extern const VkComponentMapping VULKAN_1555_SWIZZLE; @@ -47,9 +48,9 @@ public: void DeviceLost() { DestroyDeviceObjects(); } - void DeviceRestore(VulkanContext *vulkan) { - vulkan_ = vulkan; - InitDeviceObjects(); + void DeviceRestore(Draw::DrawContext *draw) { + vulkan_ = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); + InitDeviceObjects(draw); } // Note: This doesn't cache. The descriptor is for immediate use only. @@ -63,7 +64,7 @@ public: void EndFrame(); private: - void InitDeviceObjects(); + void InitDeviceObjects(Draw::DrawContext *draw); void DestroyDeviceObjects(); VulkanContext *vulkan_ = nullptr; diff --git a/Qt/QtHost.h b/Qt/QtHost.h index 79a65caa68..d8fa12f1f7 100644 --- a/Qt/QtHost.h +++ b/Qt/QtHost.h @@ -30,45 +30,45 @@ public: mainWindow = mainWindow_; } - virtual void UpdateUI() override { + void UpdateUI() override { mainWindow->updateMenus(); } - virtual void UpdateMemView() override { + void UpdateMemView() override { } - virtual void UpdateDisassembly() override { + void UpdateDisassembly() override { mainWindow->updateMenus(); } - virtual void SetDebugMode(bool mode) override { + void SetDebugMode(bool mode) override { } - virtual bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override { return true; } - virtual void ShutdownGraphics() override {} + bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override { return true; } + void ShutdownGraphics() override {} - virtual void InitSound() override; - virtual void UpdateSound() override {} - virtual void ShutdownSound() override; + void InitSound() override; + void UpdateSound() override {} + void ShutdownSound() override; // this is sent from EMU thread! Make sure that Host handles it properly! - virtual void BootDone() override { + void BootDone() override { g_symbolMap->SortSymbols(); mainWindow->Notify(MainWindowMsg::BOOT_DONE); } - virtual bool IsDebuggingEnabled() override { + bool IsDebuggingEnabled() override { #ifdef _DEBUG return true; #else return false; #endif } - virtual bool AttemptLoadSymbolMap() override { + bool AttemptLoadSymbolMap() override { auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart); return g_symbolMap->LoadSymbolMap(fn); } - virtual void NotifySymbolMapUpdated() override { g_symbolMap->SortSymbols(); } + void NotifySymbolMapUpdated() override { g_symbolMap->SortSymbols(); } void PrepareShutdown() { auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart); diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index bba1f1ae2b..f5a9300616 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -418,7 +418,7 @@ QString MainUI::InputBoxGetQString(QString title, QString defaultValue) { void MainUI::resizeGL(int w, int h) { if (UpdateScreenScale(w, h)) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); } xscale = w / this->width(); yscale = h / this->height(); diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 2560711684..26707a76e2 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,14 @@ MainWindow::MainWindow(QWidget *parent, bool fullscreen) : nextState(CORE_POWERDOWN), lastUIState(UISTATE_MENU) { +#if defined(ASSETS_DIR) + if (QFile::exists(ASSETS_DIR "icon_regular_72.png")) + setWindowIcon(QIcon(ASSETS_DIR "icon_regular_72.png")); + else + setWindowIcon(QIcon(qApp->applicationDirPath() + "/assets/icon_regular_72.png")); +#else setWindowIcon(QIcon(qApp->applicationDirPath() + "/assets/icon_regular_72.png")); +#endif SetGameTitle(""); emugl = new MainUI(this); @@ -89,7 +97,6 @@ void MainWindow::updateMenus() updateMenuGroupInt(saveStateGroup, g_Config.iCurrentStateSlot); updateMenuGroupInt(displayRotationGroup, g_Config.iInternalScreenRotation); updateMenuGroupInt(renderingResolutionGroup, g_Config.iInternalResolution); - updateMenuGroupInt(renderingModeGroup, g_Config.iRenderingMode); updateMenuGroupInt(frameSkippingGroup, g_Config.iFrameSkip); updateMenuGroupInt(frameSkippingTypeGroup, g_Config.iFrameSkipType); updateMenuGroupInt(textureFilteringGroup, g_Config.iTexFiltering); @@ -590,7 +597,7 @@ void MainWindow::createMenus() MenuTree* gameSettingsMenu = new MenuTree(this, menuBar(), QT_TR_NOOP("&Game settings")); gameSettingsMenu->add(new MenuAction(this, SLOT(languageAct()), QT_TR_NOOP("La&nguage..."))); gameSettingsMenu->add(new MenuAction(this, SLOT(controlMappingAct()), QT_TR_NOOP("C&ontrol mapping..."))); - gameSettingsMenu->add(new MenuAction(this, SLOT(displayLayoutEditorAct()), QT_TR_NOOP("Display layout editor..."))); + gameSettingsMenu->add(new MenuAction(this, SLOT(displayLayoutEditorAct()), QT_TR_NOOP("Display layout & effects..."))); gameSettingsMenu->add(new MenuAction(this, SLOT(moreSettingsAct()), QT_TR_NOOP("&More settings..."))); gameSettingsMenu->addSeparator(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) @@ -599,6 +606,9 @@ void MainWindow::createMenus() gameSettingsMenu->add(new MenuAction(this, SLOT(fullscrAct()), QT_TR_NOOP("Fu&llscreen"), QKeySequence::FullScreen)) #endif ->addEventChecked(&g_Config.bFullScreen); + gameSettingsMenu->add(new MenuAction(this, SLOT(bufferRenderAct()), QT_TR_NOOP("&Skip buffer effects"))) + ->addEventChecked(&g_Config.bSkipBufferEffects); + MenuTree* renderingResolutionMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("&Rendering resolution")); renderingResolutionGroup = new MenuActionGroup(this, renderingResolutionMenu, SLOT(renderingResolutionGroup_triggered(QAction *)), QStringList() << "&Auto" << "&1x" << "&2x" << "&3x" << "&4x" << "&5x" << "&6x" << "&7x" << "&8x" << "&9x" << "1&0x", @@ -609,10 +619,6 @@ void MainWindow::createMenus() QStringList() << "&1x" << "&2x" << "&3x" << "&4x" << "&5x" << "&6x" << "&7x" << "&8x" << "&9x" << "1&0x", QList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10); - MenuTree* renderingModeMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("Rendering m&ode")); - renderingModeGroup = new MenuActionGroup(this, renderingModeMenu, SLOT(renderingModeGroup_triggered(QAction *)), - QStringList() << "&Skip buffered effects (non-buffered, faster)" << "&Buffered rendering", - QList() << 0 << 1); MenuTree* frameSkippingMenu = new MenuTree(this, gameSettingsMenu, QT_TR_NOOP("&Frame skipping")); frameSkippingMenu->add(new MenuAction(this, SLOT(autoframeskipAct()), QT_TR_NOOP("&Auto"))) ->addEventChecked(&g_Config.bAutoFrameSkip); diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 87718b51cf..705a3dd004 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -119,31 +119,22 @@ private slots: void moreSettingsAct() { NativeMessageReceived("settings", ""); } void bufferRenderAct() { - g_Config.iRenderingMode = !g_Config.iRenderingMode; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); + NativeMessageReceived("gpu_configChanged", ""); } void linearAct() { g_Config.iTexFiltering = (g_Config.iTexFiltering != 0) ? 0 : 3; } void renderingResolutionGroup_triggered(QAction *action) { g_Config.iInternalResolution = action->data().toInt(); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); } void windowGroup_triggered(QAction *action) { SetWindowScale(action->data().toInt()); } - void displayLayoutGroup_triggered(QAction *action) { - g_Config.iSmallDisplayZoomType = action->data().toInt(); - NativeMessageReceived("gpu_resized", ""); - } - void renderingModeGroup_triggered(QAction *action) { - g_Config.iRenderingMode = action->data().toInt(); - g_Config.bAutoFrameSkip = false; - NativeMessageReceived("gpu_resized", ""); - } void autoframeskipAct() { g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; - NativeMessageReceived("gpu_resized", ""); + if (g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; + NativeMessageReceived("gpu_configChanged", ""); } } void frameSkippingGroup_triggered(QAction *action) { g_Config.iFrameSkip = action->data().toInt(); } @@ -152,19 +143,19 @@ private slots: void screenScalingFilterGroup_triggered(QAction *action) { g_Config.iBufFilter = action->data().toInt(); } void textureScalingLevelGroup_triggered(QAction *action) { g_Config.iTexScalingLevel = action->data().toInt(); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } void textureScalingTypeGroup_triggered(QAction *action) { g_Config.iTexScalingType = action->data().toInt(); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } void deposterizeAct() { g_Config.bTexDeposterize = !g_Config.bTexDeposterize; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } void transformAct() { g_Config.bHardwareTransform = !g_Config.bHardwareTransform; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } void vertexCacheAct() { g_Config.bVertexCache = !g_Config.bVertexCache; } void frameskipAct() { g_Config.iFrameSkip = !g_Config.iFrameSkip; } @@ -224,7 +215,7 @@ private: *textureScalingLevelGroup, *textureScalingTypeGroup, *screenScalingFilterGroup, *textureFilteringGroup, *frameSkippingTypeGroup, *frameSkippingGroup, - *renderingModeGroup, *renderingResolutionGroup, + *renderingResolutionGroup, *displayRotationGroup, *saveStateGroup; std::queue msgQueue_; diff --git a/README.md b/README.md index 8a9a7bc744..1fc89d2439 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,64 @@ If you want to download regularly updated builds for Android, Windows x86 and x6 For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). +What's new in 1.14 +================== +* Massive number of rendering fixes + - Water in Outrun 2006 and DiRT 2 now renders correctly (logic op fixes) ([#15960], [#16208], [#16032], [#16024], [#15967]) + - Split/Second now renders all effects correctly + - Multiple fixes workarounds for clipping/culling, both through clip planes and geometry shaders, fixing + graphical issues in many, many games and getting rid of hacks ([#16142], [#16504], [#16442], [#16383], [#16165], [#16162], [#16049], others) + - Killzone color effect now renders efficiently and correctly (in-game only, not title screen) ([#15934]) + - Ridge Racer speedometers and lens flares fixed ([#16084], [#16188], [#16115]) + - Lens flare effect fixed in Burnout Dominator, Ridge Racer, Colin McRae, several others ([#16014], [#16081], [#16076], [#16073]) + - Shadows in Colin McRae are no longer flickering (side effect of other fixes) + - Spongebob: Yellow Avenger renders correctly (previously very broken) ([#15907], [#15903]) + - Cars: Race-o-Rama, and MX vs ATV Reflex render correctly (at 1x resolution only) ([#15898], [#15907]) + - Asphalt 2 depth occlusion problems fixed ([#15854], [#15853]) + - Fix performance regression in Juiced 2 while also fixing the graphics ([#15888]) + - Silent Hill games are less broken ([#16127]) + - Depth occlusion and other problems fixed in Kurohyou (both games) and Ratchet & Clank ([#16454], [#15772], [#15728], [#15859]) + - Misshitsu no Sacrifice intro animation and Macross water rendering fixed (3D texture) ([#15727]) + - Tekken 6 Nancy laser beam fixed, plus line rendering fixes in rRootage and other games ([#16067]) + - Tiger & Bunny, Yu-Gi-Oh, GEB, and PlayView games - JPEG image display issues ([#16179], [#16184], [#15924]) + - Many, many others like Hunter x Hunter, Crash: Mind over Mutant, Boundless Trails, etc. ([#16265], [#16043], [#16379], [#15822], [#16358]) +* Software renderer performance and accuracy improvements + - Better performance ([#15998], [#16001], [#16011], [#16039], [#16054], [#16080], [#16085], [#16094], [#16102], [#16387], [#16486], [#16502], [#16518]) + - Improved accuracy, clipping ([#15999], [#16005], [#16042], [#16086], [#16117], [#16231], [#16241], [#16265], [#16274], [#16469], [#16470], [#16478], [#16480], [#16485]) +* New features + - Initial VR support added (Quest and PICO only for now, PC in the future) ([#15659], [#15901], [#16246], [#16262], [#16273]) + - MSAA antialiasing added to the Vulkan backend (desktop only) ([#16458]) + - New API for plugins to access aspect ratio, scaling and fast-forward ([#16441]), other new APIs & improvements ([#15748], [#16121], [#16187], [#16198], [#16389]) + - Read texture replacement packs directly from ZIP files ([#16304]) +* UI improvements + - New interactive Display Layout & Effects screen, replacing the old Display Layout Editor ([#16409], [#16415], [#16417], [#16445]) + - Add default shader for LCD persistence simulation ([#16531]) + - Game being played can now be seen as a background in most menus ([#16404], more) + - Reorganize speed hack settings ([#16346], [#16347], [#16348], [#16432]) +* Stability fixes + - Workaround for hangs on older Adreno GPUs ([#16422]) + - Input handling fixes for deadzones and touch controls ([#16419], [#16450]) + - Avoid game bugs in Twinbee Portable ([#16388]) and Shining Ark ([#16449]) + - Fixes to D3D9 backend issues ([#15723], [#15815], [#15926], [#16100], [#16232], [#16550]) +* IR interpreter (iOS, etc.) bug fixes + - Metal Gear Solid - Peace Walker no longer bugged out ([#16396]) + - VFPU fixes for Dissidia, others ([#16302], [#16305], [#16306]) +* Performance improvements + - Vulkan bandwidth and synchronization optimizations ([#16434], [#16099], [#16090], [#16072], [#16061], [#16060], [#16035], [#15917]) + - Lighting "ubershader" optimization to prevent hitches ([#16104], [#16111]) + - Assorted minor other improvements ([#15589], [#15843], [#16190]) + - Improve texture replacement memory usage ([#15884], [#16304], [#16314]) + - Texture upscaling speedup and fixes ([#15803], [#16125]) +* Other + - HLE/CPU accuracy improvements helping Brooktown High, Frontier Gate, Madoka Magicka, some language patches ([#16413], [#16070], [#16052], [#15930], [#15952], [#15957], more) + - Many GE debugger improvements ([#15839], [#15851], [#15894], [#15925], [#15974], [#16007], [#16047], [#16096], [#16201]) + - Optional memory alignment validation in IR mode ([#15879], [#15880]) + - Fix netplay assertion in Cars ([#16089]) + What's new in 1.13.2 ==================== * Crashfix on Android 12 when playing certain background music ([#15990]) -* Fix Star Ocean battles in D3D backends (#[15889]) +* Fix Star Ocean battles in D3D backends ([#15889]) * Minor fixes that might fix some other crashes What's new in 1.13.1 @@ -84,95 +138,12 @@ UI * Fix input focus bug ([#15560]) * New GE debugger features and other UI fixes ([#15393], [#15324], [#15377], [#15424], [#15402], [#15378], [#15338]), etc. -What's new in 1.12.3 -==================== -* Fix background music speed. A couple translation fixes. - -What's new in 1.12.2 -==================== -* Fix joystick detection bug on Android. - -What's new in 1.12.1 -==================== -* Bug fixes (control mapping fix, popup menus in the Windows debugger, a few crashfixes) - -What's new in 1.12 -================== - -Platform support: -* Add support for Android 12 Scoped Storage restrictions ([#11997]) -* iOS: Fix multitouch tracking ([#5099]) -* Android: Fix screenshot orientation on Vulkan ([#14053]) -* Linux: Improve support for system FFmpeg 3.1+ ([#14176], [#14188], [#14199]) -* libretro: Always enable function hooks ([#14145]) -* AMD: Enable Vulkan rendering on a thread ([#13864]) -* Add iOS version detection, turn off JIT on bootup if >= 14.3. ([#14201]) -* iOS: Try a different JIT detection method, thanks Halo-Michael ([#14241]) -* Windows: Restore window size correctly ([#14317]) - -Game fixes: -* Fix NBA Live 08 loading ([#8288]) -* Display Open Season title screen correctly ([#13252]) -* Fix Metal Gear Solid Peace Walker Chinese Patched blue screen ([#14127]) -* Load Ape Academy 2 correctly ([#14271]) -* Many more... - -Graphics and Sound: -* Add new texture filtering mode "Auto Max Quality" ([#14789]) -* Fix Princess Maker 5 Portable half screen in Vulkan ([#13741]) -* Fix Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off ([#14167]) -* Support texture replacement filtering overrides ([#14230]) -* Fix Yarudora Portable: Double Cast's FMVs artifacting ([#13759]) -* Fix Sims 2 Castaway/Pets EA Logo glitched out ([#13146]) -* Fix bad size & position on Japanese & Numbers & Alphabets ([#14209]) -* Implement basic depth texturing for OpenGL ([#14042]) -* Google Cardboard fixes ([#14966], [#14768]) -* Correct mini-map update in Z.H.P. ([#14069]) -* Fix crash in vertex jit on ARM32 ([#14879]) -* Add a setting for reverb volume ([#14711]) -* Option to switch to new devices or not, on Windows. - -UI: -* Add a setting for choosing background animation in PPSSPP's menus ([#14313], [#14818], [#14810], [#14347]) -* Add CRC calculation on game info screen and feedback screen ([#14000], [#14041]) -* Add a Storage tab to System Information with some path info ([#14224], [#14238]) -* Track and show memory allocation / usage information in debugger ([#14056]) -* Allow searching within the savedata manager ([#14237]) -* Enable postshaders to access previous frame ([#14528]) -* Add missing Japanese keyboard symbol ([#14548]) -* Add Reset button on crash screen, allow load state and related ([#14708]) -* Implement save state load and save undo ([#14676], [#14679], [#14697]) -* A lot of minor debugger improvements - -Controls: -* New analog stick calibration menu ([#14596]) -* Improved combo button and moved settings to Customize Touch Control -> Customize -> Custom button ([#13869]) -* Improved tilt control, allow to change axis ([#12530]) -* Add a visual means of control mapping ([#14769]) -* Add basic motion gesture support ([#13107]) -* Fix touch control DPAD not getting input when dragged over, and make touch analog drag not activate other buttons ([#14843]) -* Allow adjusting touch control analog stick head size ([#14480]) - -Adhoc/Network: -* Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data ([#14140]) -* Always enable TCPNoDelay to improve response time ([#14235]) -* Fix Teenage Mutant Ninja Turtles multiplayer ([#14284]) -* Fix FlatOut Head On multiplayer ([#14290]) -* Prevent flooding Adhoc Server with connection attempts ([#14335]) -* Fix crashing issue when leaving a multiplayer game room (ie. GTA Vice City Stories) ([#14342]) -* Fix stuck issue when scanning AP to Recruit on MGS:PW ([#14345]) -* Fix possible crash issue on blocking socket implementation (ie. Kao Challengers) ([#14466]) -* Create GameMode's socket after Master and all Replicas have been created (ie. Fading Shadows) ([#14492]) -* Reduce HLE delays due to multiplayer performance regressions (ie. Ys vs. Sora no Kiseki) ([#14513]) -* Fix socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy ([#14849]) - - Looking for [older news](history.md)? Adhoc support ------------- -Not fully functional, but some games work. Check the [Ad-Hoc section of the forum](http://forums.ppsspp.org/forumdisplay.php?fid=34) for help. +Not fully functional, but some games work. Check the [Ad-Hoc section of the forum](https://forums.ppsspp.org/forumdisplay.php?fid=34) for help. Credit goes to: - ANR2ME @@ -183,68 +154,6 @@ Credit goes to: [comment]: # (LINK_LIST_BEGIN_HERE) -[#11997]: https://github.com/hrydgard/ppsspp/issues/11997 "Android 12 scoped storage hell" -[#5099]: https://github.com/hrydgard/ppsspp/issues/5099 "IOS touch controls problems." -[#14053]: https://github.com/hrydgard/ppsspp/issues/14053 "Toggle screenshot minor issue." -[#14176]: https://github.com/hrydgard/ppsspp/issues/14176 "Remove deprecated API calls for new FFmpeg 4.3.x" -[#14188]: https://github.com/hrydgard/ppsspp/issues/14188 "Additional fixes for FFmpeg 3.1+" -[#14199]: https://github.com/hrydgard/ppsspp/issues/14199 "Mpeg: Set low latency flag for video decode" -[#14145]: https://github.com/hrydgard/ppsspp/issues/14145 "libretro: Remove \"Unsafe FuncReplacements\" option." -[#13864]: https://github.com/hrydgard/ppsspp/issues/13864 "Vulkan: Remove #10097 hack for newer AMD drivers" -[#14201]: https://github.com/hrydgard/ppsspp/issues/14201 "Add iOS version detection, turn off JIT on bootup if >= 14.3." -[#14241]: https://github.com/hrydgard/ppsspp/issues/14241 "iOS: Try a different JIT detection method, thanks Halo-Michael." -[#14317]: https://github.com/hrydgard/ppsspp/issues/14317 "Window size restarts on closing" -[#8288]: https://github.com/hrydgard/ppsspp/issues/8288 "NBA live 08 Invalid address and hang" -[#14069]: https://github.com/hrydgard/ppsspp/issues/14069 "Mini-Map in Z.H.P. Updates Incorrectly Without Software Rendering" -[#13252]: https://github.com/hrydgard/ppsspp/issues/13252 "Open Season Title Screen does not display" -[#14127]: https://github.com/hrydgard/ppsspp/issues/14127 "Metal Gear Solid Peace Walker Chinese Patched blue screen" -[#14271]: https://github.com/hrydgard/ppsspp/issues/14271 "Ape Academy 2 is broken on versions after 1.8.0(?) - tested on latest nightly and 1.11.3" -[#13741]: https://github.com/hrydgard/ppsspp/issues/13741 "Princess Maker 5 Portable half screen in Vulkan" -[#14167]: https://github.com/hrydgard/ppsspp/issues/14167 "[Android] Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off" -[#14230]: https://github.com/hrydgard/ppsspp/issues/14230 "Support texture replacement filtering overrides" -[#13759]: https://github.com/hrydgard/ppsspp/issues/13759 "Yarudora Portable: Double Cast" -[#13146]: https://github.com/hrydgard/ppsspp/issues/13146 "Sims 2 Castaway/Pets EA Logo glitched out - 1.10.2" -[#14789]: https://github.com/hrydgard/ppsspp/issues/14789 "Add new texture filtering mode \"Auto Max Quality\"" -[#14209]: https://github.com/hrydgard/ppsspp/issues/14209 "Fix Size & Position jpn0.pgf/ltn0.pgf/ltn2.pgf/ltn4.pgf/ltn6.pgf" -[#14042]: https://github.com/hrydgard/ppsspp/issues/14042 "Implement basic depth texturing for OpenGL" -[#14966]: https://github.com/hrydgard/ppsspp/issues/14966 "Config: Correct cardboard setting ini load" -[#14768]: https://github.com/hrydgard/ppsspp/issues/14768 "Fix the math in cardboard VR mode for wide aspect ratios" -[#14879]: https://github.com/hrydgard/ppsspp/issues/14879 "vertexjit: Correct morph flag alpha check assert" -[#14313]: https://github.com/hrydgard/ppsspp/issues/14313 "Add a setting for choosing background animation in PPSSPP's menus" -[#14818]: https://github.com/hrydgard/ppsspp/issues/14818 "Focus based moving background" -[#14810]: https://github.com/hrydgard/ppsspp/issues/14810 "Wave animation" -[#14347]: https://github.com/hrydgard/ppsspp/issues/14347 "UI: Add BG animation for recent games" -[#14041]: https://github.com/hrydgard/ppsspp/issues/14041 "UI: Add button to show CRC on feedback screen" -[#14224]: https://github.com/hrydgard/ppsspp/issues/14224 "Add a Storage tab to System Information with some path info" -[#14238]: https://github.com/hrydgard/ppsspp/issues/14238 "UI: Wrap long info items and cleanup storage display" -[#14056]: https://github.com/hrydgard/ppsspp/issues/14056 "Track memory allocations and writes for debug info" -[#14237]: https://github.com/hrydgard/ppsspp/issues/14237 "Add initial search to savedata manager" -[#14528]: https://github.com/hrydgard/ppsspp/issues/14528 "Postshader: Let shaders use the previous frame" -[#14548]: https://github.com/hrydgard/ppsspp/issues/14548 "Add some PPSSPP's Japanese keyboard" -[#14708]: https://github.com/hrydgard/ppsspp/issues/14708 "Add Reset button on crash screen, allow load state and related" -[#14676]: https://github.com/hrydgard/ppsspp/issues/14676 "Add savestate undo UI" -[#14679]: https://github.com/hrydgard/ppsspp/issues/14679 "Savestate load undo" -[#14697]: https://github.com/hrydgard/ppsspp/issues/14697 "Add undo last save as well" -[#14596]: https://github.com/hrydgard/ppsspp/issues/14596 "Replace the \"Test Analogs\" screen with a new screen that lets you directly try the settings." -[#13869]: https://github.com/hrydgard/ppsspp/issues/13869 "Make combo button more generic" -[#12530]: https://github.com/hrydgard/ppsspp/issues/12530 "Allow tilt input on Z instead of X" -[#14000]: https://github.com/hrydgard/ppsspp/issues/14000 "Add CRC32 calc" -[#14769]: https://github.com/hrydgard/ppsspp/issues/14769 "Add a visual means of control mapping" -[#13107]: https://github.com/hrydgard/ppsspp/issues/13107 "Basic mappable motion gesture" -[#14843]: https://github.com/hrydgard/ppsspp/issues/14843 "DPad drag fixes" -[#14480]: https://github.com/hrydgard/ppsspp/issues/14480 "Configurable analog head size" -[#14140]: https://github.com/hrydgard/ppsspp/issues/14140 "[Adhoc] Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data" -[#14235]: https://github.com/hrydgard/ppsspp/issues/14235 "[Adhoc] Always enable TCPNoDelay to improve response time" -[#14284]: https://github.com/hrydgard/ppsspp/issues/14284 "[Adhoc] Fix Teenage Mutant Ninja Turtles Multiplayer" -[#14290]: https://github.com/hrydgard/ppsspp/issues/14290 "Fix FlatOut Head On multiplayer." -[#14335]: https://github.com/hrydgard/ppsspp/issues/14335 "[Adhoc] Prevent flooding Adhoc Server with connection attempts" -[#14342]: https://github.com/hrydgard/ppsspp/issues/14342 "[AdhocMatching] Fix crashing issue when leaving a multiplayer game room" -[#14345]: https://github.com/hrydgard/ppsspp/issues/14345 "[APctl] Fix stuck issue when scanning AP to Recruit on MGS:PW" -[#14466]: https://github.com/hrydgard/ppsspp/issues/14466 "[Adhoc] Fix possible crash issue on blocking socket implementation." -[#14492]: https://github.com/hrydgard/ppsspp/issues/14492 "[AdhocGameMode] Create GameMode's socket after Master and all Replicas have been created" -[#14513]: https://github.com/hrydgard/ppsspp/issues/14513 "[Adhoc] Reducing HLE delays due to Mutiplayer performance regressions" -[#14849]: https://github.com/hrydgard/ppsspp/issues/14849 "[Adhoc] Fix Socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy" -[#14711]: https://github.com/hrydgard/ppsspp/issues/14711 "Sas: Add option to control reverb volume" [#15237]: https://github.com/hrydgard/ppsspp/issues/15237 "Path: Check for PSP case insensitively" [#15487]: https://github.com/hrydgard/ppsspp/issues/15487 "Save textures on background tasks when texture dumping is enabled." [#15645]: https://github.com/hrydgard/ppsspp/issues/15645 "UI: Add analog speed limit mapping" @@ -306,3 +215,145 @@ Credit goes to: [#15740]: https://github.com/hrydgard/ppsspp/issues/15740 "Replacement: Clear cache on disable" [#15734]: https://github.com/hrydgard/ppsspp/issues/15734 "Better pt-pt translation" [#15733]: https://github.com/hrydgard/ppsspp/issues/15733 "Fix bug in blue-to-alpha - alpha blending could be on when it shouldn't be." +[#15960]: https://github.com/hrydgard/ppsspp/issues/15960 "Enable logic op emulation in-shader" +[#16208]: https://github.com/hrydgard/ppsspp/issues/16208 "GPU: Respect stencil state in shader blend" +[#16032]: https://github.com/hrydgard/ppsspp/issues/16032 "Fix the water in Outrun when no logic ops" +[#16024]: https://github.com/hrydgard/ppsspp/issues/16024 "GPU: Fix simulating logicop with blend and shader" +[#15967]: https://github.com/hrydgard/ppsspp/issues/15967 "Fix BlueToAlpha mode, re-enable it for Outrun and DiRT" +[#16142]: https://github.com/hrydgard/ppsspp/issues/16142 "Implement geometry shader for range culling" +[#16504]: https://github.com/hrydgard/ppsspp/issues/16504 "GPU: Use accurate depth for depth range hack" +[#16442]: https://github.com/hrydgard/ppsspp/issues/16442 "Vulkan: Only use geometry shaders with accurate depth" +[#16383]: https://github.com/hrydgard/ppsspp/issues/16383 "GPU: Automatically reduce depth range on == test" +[#16165]: https://github.com/hrydgard/ppsspp/issues/16165 "Vulkan: Clip clamped depth in geometry shader" +[#16162]: https://github.com/hrydgard/ppsspp/issues/16162 "Implement negative Z clipping in geometry shader" +[#16049]: https://github.com/hrydgard/ppsspp/issues/16049 "GPU: Clip depth properly when also clamping" +[#15934]: https://github.com/hrydgard/ppsspp/issues/15934 "Split the main framebuffer in Killzone, to avoid texturing-from-current-rendertarget" +[#16084]: https://github.com/hrydgard/ppsspp/issues/16084 "Fix Ridge Racer lens flares - ignore stride if texHeight == 1, when matching tex/fb" +[#16188]: https://github.com/hrydgard/ppsspp/issues/16188 "Fix depal bounds with dynamic CLUT. Fixes lens flare glitches in Ridge Racer" +[#16115]: https://github.com/hrydgard/ppsspp/issues/16115 "Add compatibility flag for loading pixels on framebuffer create using nearest filtering" +[#16014]: https://github.com/hrydgard/ppsspp/issues/16014 "Texture depal using CLUT loaded from framebuffers, and more. Fixes Burnout Dominator lens flare" +[#16081]: https://github.com/hrydgard/ppsspp/issues/16081 "Fix green flashes with Burnout Dominator lens flare" +[#16076]: https://github.com/hrydgard/ppsspp/issues/16076 "Don't try to replace or scale CLUT8-on-GPU textures." +[#16073]: https://github.com/hrydgard/ppsspp/issues/16073 "CLUTs can be loaded from small rectangular textures. Need to linearize." +[#15907]: https://github.com/hrydgard/ppsspp/issues/15907 "Reinterpret between 32 and 16 bit texture formats" +[#15903]: https://github.com/hrydgard/ppsspp/issues/15903 "Remove support for framebuffers changing stride (already unreachable)." +[#15898]: https://github.com/hrydgard/ppsspp/issues/15898 "Rendering issues in Tantalus Media games (Spongebob, MX ATV, etc)" +[#15854]: https://github.com/hrydgard/ppsspp/issues/15854 "Use sequence numbers instead of a tracking array for depth buffers" +[#15853]: https://github.com/hrydgard/ppsspp/issues/15853 "Framebuffer-bind sequence numbers" +[#15888]: https://github.com/hrydgard/ppsspp/issues/15888 "Copy color from overlapping framebuffers on bind, under certain conditions" +[#16127]: https://github.com/hrydgard/ppsspp/issues/16127 "Fixes for Silent Hill: Origins (depth buffer reassignment, eliminate readback)" +[#16454]: https://github.com/hrydgard/ppsspp/issues/16454 "GPU: Support framebuf depal from rendered CLUT" +[#15772]: https://github.com/hrydgard/ppsspp/issues/15772 "Add support for binding the depth buffer as a color target. Fixes Kurohyo depth sorting" +[#15728]: https://github.com/hrydgard/ppsspp/issues/15728 "Better ways to deal with overlapping render targets" +[#15859]: https://github.com/hrydgard/ppsspp/issues/15859 "Allow binding depth as 565" +[#15727]: https://github.com/hrydgard/ppsspp/issues/15727 "Implement the PSP's equal-size mips \"3D texturing\"" +[#16067]: https://github.com/hrydgard/ppsspp/issues/16067 "GPU: Account for w properly in lines, fixing width" +[#16179]: https://github.com/hrydgard/ppsspp/issues/16179 "Correct size and YUV order for jpeg decoding" +[#16184]: https://github.com/hrydgard/ppsspp/issues/16184 "GPU: Hook Gods Eater Burst avatar read" +[#15924]: https://github.com/hrydgard/ppsspp/issues/15924 "Add support for reading depth buffers to the PackFramebufferSync function" +[#16265]: https://github.com/hrydgard/ppsspp/issues/16265 "GPU: Respect world matrix and reverse flag w/o normals" +[#16043]: https://github.com/hrydgard/ppsspp/issues/16043 "Consider the Adreno and Mali stencil-discard bugs the same." +[#16379]: https://github.com/hrydgard/ppsspp/issues/16379 "Fix alpha/stencil replace on Adreno when color masked" +[#15822]: https://github.com/hrydgard/ppsspp/issues/15822 "GPU: Write stencil fail to alpha is RGB masked" +[#16358]: https://github.com/hrydgard/ppsspp/issues/16358 "TexCache: Fix 16->32 colors with CLUT start pos" +[#15998]: https://github.com/hrydgard/ppsspp/issues/15998 "softgpu: Allow almost flat rectangles to go fast" +[#16001]: https://github.com/hrydgard/ppsspp/issues/16001 "softgpu: Check depth test early on simple stencil" +[#16011]: https://github.com/hrydgard/ppsspp/issues/16011 "Detect more triangles as rectangles in softgpu" +[#16039]: https://github.com/hrydgard/ppsspp/issues/16039 "softgpu: Run early Z tests in fast rect path" +[#16054]: https://github.com/hrydgard/ppsspp/issues/16054 "softgpu: Reduce some flushing / flushing cost" +[#16080]: https://github.com/hrydgard/ppsspp/issues/16080 "softgpu: Avoid unnecessary flushing for curves" +[#16085]: https://github.com/hrydgard/ppsspp/issues/16085 "softgpu: Cache reused indexed verts" +[#16094]: https://github.com/hrydgard/ppsspp/issues/16094 "softgpu: Optimize rectangle sampling/blending used in bloom" +[#16102]: https://github.com/hrydgard/ppsspp/issues/16102 "softgpu: Avoid waiting for a thread to drain" +[#16387]: https://github.com/hrydgard/ppsspp/issues/16387 "softgpu: Use threads on self-render if safe" +[#16486]: https://github.com/hrydgard/ppsspp/issues/16486 "softgpu: Apply optimizations to states generically" +[#16502]: https://github.com/hrydgard/ppsspp/issues/16502 "A few more softgpu optimizations for alpha blend/test" +[#16518]: https://github.com/hrydgard/ppsspp/issues/16518 "softgpu: Expand fast path to all fb formats" +[#15999]: https://github.com/hrydgard/ppsspp/issues/15999 "softgpu: Clamp/wrap textures at 512 pixels" +[#16005]: https://github.com/hrydgard/ppsspp/issues/16005 "softgpu: Correct accuracy of fog calculation" +[#16042]: https://github.com/hrydgard/ppsspp/issues/16042 "softgpu: Refactor imm prim handling to support fog/color1" +[#16086]: https://github.com/hrydgard/ppsspp/issues/16086 "softgpu: Fix self-render detect in Ridge Racer" +[#16117]: https://github.com/hrydgard/ppsspp/issues/16117 "Correct texture projection issues, mainly in softgpu" +[#16231]: https://github.com/hrydgard/ppsspp/issues/16231 "softgpu: Cull a triangle with all negative w" +[#16241]: https://github.com/hrydgard/ppsspp/issues/16241 "softgpu: Correct linear interp for uneven positions" +[#16274]: https://github.com/hrydgard/ppsspp/issues/16274 "Correct accuracy of bounding box test" +[#16469]: https://github.com/hrydgard/ppsspp/issues/16469 "Correct block transfer overlap and wrapping behavior" +[#16470]: https://github.com/hrydgard/ppsspp/issues/16470 "softgpu: Correctly fix inversions, matching tests" +[#16478]: https://github.com/hrydgard/ppsspp/issues/16478 "softgpu: Interpolate Z for 3D lines" +[#16480]: https://github.com/hrydgard/ppsspp/issues/16480 "softgpu: Cull verts outside post-viewport Z" +[#16485]: https://github.com/hrydgard/ppsspp/issues/16485 "softgpu: Handle infnan fog coefficients better" +[#15659]: https://github.com/hrydgard/ppsspp/issues/15659 "Oculus Quest native support" +[#15901]: https://github.com/hrydgard/ppsspp/issues/15901 "OpenXR - Stereoscopic rendering" +[#16246]: https://github.com/hrydgard/ppsspp/issues/16246 "VR: Add the VR code to all builds. Remove IsVRBuild calls from the renderer." +[#16262]: https://github.com/hrydgard/ppsspp/issues/16262 "OpenXR - Add an option to adjust camera distance" +[#16273]: https://github.com/hrydgard/ppsspp/issues/16273 "Vulkan multiview rendering" +[#16458]: https://github.com/hrydgard/ppsspp/issues/16458 "Implement MSAA support for desktop GPUs in Vulkan" +[#16441]: https://github.com/hrydgard/ppsspp/issues/16441 "Exposed more emulator things to devctl api" +[#15748]: https://github.com/hrydgard/ppsspp/issues/15748 "Windows: Add a simple window message to get the base pointer." +[#16121]: https://github.com/hrydgard/ppsspp/issues/16121 "Debugger: Add API to scan memory for funcs" +[#16187]: https://github.com/hrydgard/ppsspp/issues/16187 "Remote API: hle.func.removeRange added" +[#16198]: https://github.com/hrydgard/ppsspp/issues/16198 "Readback stencil buffer for debugger on GLES" +[#16389]: https://github.com/hrydgard/ppsspp/issues/16389 "Make breakpoints work better in interpreter" +[#16304]: https://github.com/hrydgard/ppsspp/issues/16304 "Improve texture replacement cache and allow read from zip" +[#16409]: https://github.com/hrydgard/ppsspp/issues/16409 "Preserve framebuffer on pause screen even if render resolution is changed" +[#16415]: https://github.com/hrydgard/ppsspp/issues/16415 "Display layout editor - Remove editing widget, just use the background directly" +[#16417]: https://github.com/hrydgard/ppsspp/issues/16417 "Move post processing settings to the Display Layout Editor" +[#16445]: https://github.com/hrydgard/ppsspp/issues/16445 "New screen size controls on Display Layout & Effects screen" +[#16531]: https://github.com/hrydgard/ppsspp/issues/16531 "iota97's \"Motion blur\" - LCD persistence shader, plus fixes to make it work with OpenGL" +[#16404]: https://github.com/hrydgard/ppsspp/issues/16404 "Make the pause screen \"transparent\"" +[#16346]: https://github.com/hrydgard/ppsspp/issues/16346 "Change the \"Retain changed textures\" option into a compat.ini option." +[#16347]: https://github.com/hrydgard/ppsspp/issues/16347 "Always skin in decode for software transform and rendering" +[#16348]: https://github.com/hrydgard/ppsspp/issues/16348 "Speed hack setting reorganization" +[#16432]: https://github.com/hrydgard/ppsspp/issues/16432 "Cleanup graphics settings list" +[#16422]: https://github.com/hrydgard/ppsspp/issues/16422 "Add compat flag / bug check for games on old Adreno/GL affected" +[#16419]: https://github.com/hrydgard/ppsspp/issues/16419 "Stick input: Fix issue where deadzone noise from one device could drown out signal from another." +[#16450]: https://github.com/hrydgard/ppsspp/issues/16450 "UI: Fix right analog with single button" +[#16388]: https://github.com/hrydgard/ppsspp/issues/16388 "Twinbee Portable: Add compat flag to avoid game bug with some languages" +[#16449]: https://github.com/hrydgard/ppsspp/issues/16449 "Blind workaround for Shining Ark circle button problem" +[#15723]: https://github.com/hrydgard/ppsspp/issues/15723 "D3D9 state cache cleanup" +[#15815]: https://github.com/hrydgard/ppsspp/issues/15815 "Depth blit using raster" +[#15926]: https://github.com/hrydgard/ppsspp/issues/15926 "Implement shader blending for D3D9" +[#16100]: https://github.com/hrydgard/ppsspp/issues/16100 "D3D9: Allow INTZ depth buffers more correctly" +[#16232]: https://github.com/hrydgard/ppsspp/issues/16232 "D3D9: Correct scissor state cache in Draw" +[#16550]: https://github.com/hrydgard/ppsspp/issues/16550 "Hide the D3D9 option on Intel Xe graphics." +[#16396]: https://github.com/hrydgard/ppsspp/issues/16396 "Correct misbehavior on uninitialized values in IR" +[#16302]: https://github.com/hrydgard/ppsspp/issues/16302 "Handle vrot overlap and vscl/vmscl prefixes more accurately" +[#16305]: https://github.com/hrydgard/ppsspp/issues/16305 "irjit: Fix unordered float compares" +[#16306]: https://github.com/hrydgard/ppsspp/issues/16306 "irjit: Correct prefix validation" +[#16434]: https://github.com/hrydgard/ppsspp/issues/16434 "Vulkan: Use stencil export when available" +[#16099]: https://github.com/hrydgard/ppsspp/issues/16099 "Vulkan: Avoid allocating depth images for stuff like temp copies, depal buffers etc." +[#16090]: https://github.com/hrydgard/ppsspp/issues/16090 "Simplify synchronization in VulkanRenderManager" +[#16072]: https://github.com/hrydgard/ppsspp/issues/16072 "Vulkan: Don't have renderpasses store/load depth buffers when we don't use them" +[#16061]: https://github.com/hrydgard/ppsspp/issues/16061 "Vulkan: Submit main command buffer before acquiring the swapchain image" +[#16060]: https://github.com/hrydgard/ppsspp/issues/16060 "Vulkan FrameData refactor" +[#16035]: https://github.com/hrydgard/ppsspp/issues/16035 "Vulkan: \"Acquire\" the image from the swapchain as late as possible in the frame" +[#15917]: https://github.com/hrydgard/ppsspp/issues/15917 "Vulkan bandwidth optimizations (configure renderpass load/store better)" +[#16104]: https://github.com/hrydgard/ppsspp/issues/16104 "Generate \"Ubershaders\" that can handle all lighting configurations" +[#16111]: https://github.com/hrydgard/ppsspp/issues/16111 "Always do the vertex shader part of the fog computation." +[#15589]: https://github.com/hrydgard/ppsspp/issues/15589 "Vulkan: Parallelize GLSL compilation" +[#15843]: https://github.com/hrydgard/ppsspp/issues/15843 "GPU: Skip fb create upload when clearing" +[#16190]: https://github.com/hrydgard/ppsspp/issues/16190 "Reduce IO primarily during save operations" +[#15884]: https://github.com/hrydgard/ppsspp/issues/15884 "Replacement: Read files only within time budget" +[#16314]: https://github.com/hrydgard/ppsspp/issues/16314 "UI: Install textures as a zip if supported" +[#15803]: https://github.com/hrydgard/ppsspp/issues/15803 "Reimplement bicubic upscaling." +[#16125]: https://github.com/hrydgard/ppsspp/issues/16125 "Remove alpha ignore in xbrz texture shaders." +[#16413]: https://github.com/hrydgard/ppsspp/issues/16413 "Kernel: Respect partition param in heap funcs" +[#16070]: https://github.com/hrydgard/ppsspp/issues/16070 "Kernel: Match index lookup behavior for tls" +[#16052]: https://github.com/hrydgard/ppsspp/issues/16052 "HLE: sceKernelAllocPartitionMemory volatile memory support (partition 5)" +[#15930]: https://github.com/hrydgard/ppsspp/issues/15930 "Fix sceKernelUnlockMutex timing" +[#15952]: https://github.com/hrydgard/ppsspp/issues/15952 "interp: Handle jumps in branch delay slots better" +[#15957]: https://github.com/hrydgard/ppsspp/issues/15957 "Handle branch/jump in branch delay slots more accurately" +[#15839]: https://github.com/hrydgard/ppsspp/issues/15839 "GE debugger: Allow displaying two tabs at once, separate DL view" +[#15851]: https://github.com/hrydgard/ppsspp/issues/15851 "After recording a GE dump, open an explorer window pointing at the file" +[#15894]: https://github.com/hrydgard/ppsspp/issues/15894 "GE Debugger: Record only one flip if display framebuf not changed, step on vsync" +[#15925]: https://github.com/hrydgard/ppsspp/issues/15925 "GE Debugger: Improve display list disasm" +[#15974]: https://github.com/hrydgard/ppsspp/issues/15974 "Add breakpoint conditions to GE debugger" +[#16007]: https://github.com/hrydgard/ppsspp/issues/16007 "GE Debugger: Add fields to register expressions" +[#16047]: https://github.com/hrydgard/ppsspp/issues/16047 "GE Debugger: Allow search" +[#16096]: https://github.com/hrydgard/ppsspp/issues/16096 "GE Debugger: Add option to track pixel in preview" +[#16201]: https://github.com/hrydgard/ppsspp/issues/16201 "GE Debugger: Normalize framebuffer texture preview" +[#15879]: https://github.com/hrydgard/ppsspp/issues/15879 "irjit: Validate alignment in slow memory mode" +[#15880]: https://github.com/hrydgard/ppsspp/issues/15880 "Core: Show exception on misaligned jump" +[#16089]: https://github.com/hrydgard/ppsspp/issues/16089 "[AdhocMatching] Fix assertion issue when playing Cars over public adhoc server." +[#15990]: https://github.com/hrydgard/ppsspp/issues/15990 "Atrac3+: Allocate some extra" +[#15889]: https://github.com/hrydgard/ppsspp/issues/15889 "Correct D3D viewport offset sign in sw transform" \ No newline at end of file diff --git a/SDL/SDLGLGraphicsContext.cpp b/SDL/SDLGLGraphicsContext.cpp index 492005a1f4..945c9a950e 100644 --- a/SDL/SDLGLGraphicsContext.cpp +++ b/SDL/SDLGLGraphicsContext.cpp @@ -394,7 +394,9 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: if (gl_extensions.IsCoreContext) { glewExperimental = true; } - if (GLEW_OK != glewInit()) { + GLenum glew_err = glewInit(); + // glx is not required, igore. + if (glew_err != GLEW_OK && glew_err != GLEW_ERROR_NO_GLX_DISPLAY) { printf("Failed to initialize glew!\n"); return 1; } diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index b09a64d5dd..4158600698 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -569,9 +569,10 @@ int main(int argc, char *argv[]) { Uint32 mode = 0; for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i],"--fullscreen")) + if (!strcmp(argv[i],"--fullscreen")) { mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; - else if (set_xres == -2) + g_Config.iForceFullScreen = 1; + } else if (set_xres == -2) set_xres = parseInt(argv[i]); else if (set_yres == -2) set_yres = parseInt(argv[i]); @@ -657,7 +658,8 @@ int main(int argc, char *argv[]) { if (mode & SDL_WINDOW_FULLSCREEN_DESKTOP) { pixel_xres = g_DesktopWidth; pixel_yres = g_DesktopHeight; - g_Config.iForceFullScreen = 1; + if (g_Config.iForceFullScreen == -1) + g_Config.bFullScreen = true; } else { // set a sensible default resolution (2x) pixel_xres = 480 * 2 * set_scale; @@ -665,7 +667,8 @@ int main(int argc, char *argv[]) { if (portrait) { std::swap(pixel_xres, pixel_yres); } - g_Config.iForceFullScreen = 0; + if (g_Config.iForceFullScreen == -1) + g_Config.bFullScreen = false; } set_dpi = 1.0f / set_dpi; @@ -770,7 +773,13 @@ int main(int argc, char *argv[]) { SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); char iconPath[PATH_MAX]; +#if defined(ASSETS_DIR) + snprintf(iconPath, PATH_MAX, "%sicon_regular_72.png", ASSETS_DIR); + if (access(iconPath, F_OK) != 0) + snprintf(iconPath, PATH_MAX, "%sassets/icon_regular_72.png", SDL_GetBasePath() ? SDL_GetBasePath() : ""); +#else snprintf(iconPath, PATH_MAX, "%sassets/icon_regular_72.png", SDL_GetBasePath() ? SDL_GetBasePath() : ""); +#endif int width = 0, height = 0; unsigned char *imageData; if (pngLoad(iconPath, &width, &height, &imageData) == 1) { diff --git a/Tools/langtool/src/inifile.rs b/Tools/langtool/src/inifile.rs index ac109af0f7..c70f4636ec 100644 --- a/Tools/langtool/src/inifile.rs +++ b/Tools/langtool/src/inifile.rs @@ -111,6 +111,10 @@ impl IniFile { } } // Reached the end for some reason? Add it. + // Also add an empty line to the previous section. + if let Some(last) = self.sections.last_mut() { + last.lines.push("".into()); + } self.sections.push(section.clone()); true } diff --git a/Tools/langtool/src/main.rs b/Tools/langtool/src/main.rs index 6b99a272d3..99107fff3a 100644 --- a/Tools/langtool/src/main.rs +++ b/Tools/langtool/src/main.rs @@ -11,6 +11,8 @@ use structopt::StructOpt; struct Opt { #[structopt(subcommand)] cmd: Command, + #[structopt(short, long)] + dry_run: bool, } #[derive(StructOpt, Debug)] @@ -18,6 +20,10 @@ enum Command { CopyMissingLines {}, CommentUnknownLines {}, RemoveUnknownLines {}, + AddNewKey { + section: String, + key: String, + }, MoveKey { old: String, new: String, @@ -41,6 +47,10 @@ fn copy_missing_lines(reference_ini: &IniFile, target_ini: &mut IniFile) -> io:: //target_section.remove_lines_if_not_in(reference_section); target_section.comment_out_lines_if_not_in(reference_section); } + } else { + // Note: insert_section_if_missing will copy the entire section, + // no need to loop over the lines here. + println!("Inserted missing section: {}", reference_section.name); } } Ok(()) @@ -89,6 +99,15 @@ fn remove_key(target_ini: &mut IniFile, section: &str, key: &str) -> io::Result< Ok(()) } +fn add_new_key(target_ini: &mut IniFile, section: &str, key: &str) -> io::Result<()> { + if let Some(section) = target_ini.get_section_mut(section) { + let _ = section.insert_line_if_missing(&format!("{} = {}", key, key)); + } else { + println!("No section {}", section); + } + Ok(()) +} + fn main() { let opt = Opt::from_args(); @@ -97,15 +116,16 @@ fn main() { let mut filenames = args; let root = "../../assets/lang"; - let reference_file = "en_US.ini"; + let reference_ini_filename = "en_US.ini"; - let reference_ini = IniFile::parse(&format!("{}/{}", root, reference_file)).unwrap(); + let mut reference_ini = + IniFile::parse(&format!("{}/{}", root, reference_ini_filename)).unwrap(); if filenames.is_empty() { // Grab them all. for path in std::fs::read_dir(root).unwrap() { let path = path.unwrap(); - if path.file_name() == reference_file { + if path.file_name() == reference_ini_filename { continue; } let filename = path.file_name(); @@ -118,6 +138,7 @@ fn main() { } for filename in filenames { + let reference_ini = &reference_ini; if filename == "langtool" { // Get this from cargo run for some reason. continue; @@ -137,12 +158,16 @@ fn main() { Command::RemoveUnknownLines {} => { deal_with_unknown_lines(&reference_ini, &mut target_ini, true).unwrap(); } + Command::AddNewKey { + ref section, + ref key, + } => add_new_key(&mut target_ini, section, key).unwrap(), Command::MoveKey { ref old, ref new, ref key, } => { - move_key(&mut target_ini, &old, &new, &key).unwrap(); + move_key(&mut target_ini, old, new, key).unwrap(); } Command::RemoveKey { ref section, @@ -152,8 +177,38 @@ fn main() { } } - target_ini.write().unwrap(); + if !opt.dry_run { + target_ini.write().unwrap(); + } } - // println!("{:#?}", target_ini); + println!("Langtool processing {}", reference_ini_filename); + + // Some commands also apply to the reference ini. + match opt.cmd { + Command::AddNewKey { + ref section, + ref key, + } => { + add_new_key(&mut reference_ini, section, key).unwrap(); + } + Command::MoveKey { + ref old, + ref new, + ref key, + } => { + move_key(&mut reference_ini, old, new, key).unwrap(); + } + Command::RemoveKey { + ref section, + ref key, + } => { + remove_key(&mut reference_ini, section, key).unwrap(); + } + _ => {} + } + + if !opt.dry_run { + reference_ini.write().unwrap(); + } } diff --git a/Tools/langtool/src/section.rs b/Tools/langtool/src/section.rs index dbb097832a..f57c2e3563 100644 --- a/Tools/langtool/src/section.rs +++ b/Tools/langtool/src/section.rs @@ -96,9 +96,11 @@ impl Section { continue; } if !other.lines.iter().any(|line| line.starts_with(prefix)) { - println!("Commenting out: {}", line); - // Comment out the line. - *line = "#".to_owned() + line; + if !prefix.contains("URL") { + println!("Commenting out: {}", line); + // Comment out the line. + *line = "#".to_owned() + line; + } } } } diff --git a/UI/ComboKeyMappingScreen.cpp b/UI/ComboKeyMappingScreen.cpp index d4c8a814b6..4af85552c1 100644 --- a/UI/ComboKeyMappingScreen.cpp +++ b/UI/ComboKeyMappingScreen.cpp @@ -271,7 +271,7 @@ void ComboKeyScreen::CreateViews() { } } -static uint64_t arrayToInt(bool ary[ARRAY_SIZE(CustomKey::comboKeyList)]) { +static uint64_t arrayToInt(const bool ary[ARRAY_SIZE(CustomKey::comboKeyList)]) { uint64_t value = 0; for (int i = ARRAY_SIZE(CustomKey::comboKeyList)-1; i >= 0; i--) { value |= ary[i] ? 1 : 0; diff --git a/UI/ComboKeyMappingScreen.h b/UI/ComboKeyMappingScreen.h index c2ed6396d8..54cc86607c 100644 --- a/UI/ComboKeyMappingScreen.h +++ b/UI/ComboKeyMappingScreen.h @@ -24,9 +24,9 @@ namespace UI { class CheckBox; } -class ComboKeyScreen : public UIDialogScreenWithBackground { +class ComboKeyScreen : public UIDialogScreenWithGameBackground { public: - ComboKeyScreen(int id): id_(id) {} + ComboKeyScreen(const Path &gamePath, int id) : UIDialogScreenWithGameBackground(gamePath), id_(id) {} const char *tag() const override { return "ComboKey"; } diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index f6255ad4e3..9ca3bb5f74 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -27,6 +27,7 @@ #include "Common/UI/Context.h" #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/Data/Color/RGBAUtil.h" @@ -141,14 +142,14 @@ void SingleControlMapper::Refresh() { std::string keyName = KeyMap::GetKeyOrAxisName(mappings[i].keyCode); LinearLayout *row = rightColumn->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); - row->SetSpacing(1.0f); + row->SetSpacing(2.0f); rows_.push_back(row); Choice *c = row->Add(new Choice(deviceName + "." + keyName, new LinearLayoutParams(FILL_PARENT, itemH, 1.0f))); c->SetTag(StringFromFormat("%d_Change%d", (int)i, pspKey_)); c->OnClick.Handle(this, &SingleControlMapper::OnReplace); - Choice *d = row->Add(new Choice(" X ", new LayoutParams(WRAP_CONTENT, itemH))); + Choice *d = row->Add(new Choice(ImageID("I_TRASHCAN"), new LayoutParams(WRAP_CONTENT, itemH))); d->SetTag(StringFromFormat("%d_Del%d", (int)i, pspKey_)); d->OnClick.Handle(this, &SingleControlMapper::OnDelete); } @@ -278,7 +279,8 @@ void ControlMappingScreen::update() { RecreateViews(); } - UIDialogScreenWithBackground::update(); + UIDialogScreenWithGameBackground::update(); + SetVRAppMode(VRAppMode::VR_MENU_MODE); } UI::EventReturn ControlMappingScreen::OnClearMapping(UI::EventParams ¶ms) { @@ -307,7 +309,7 @@ UI::EventReturn ControlMappingScreen::OnAutoConfigure(UI::EventParams ¶ms) { } UI::EventReturn ControlMappingScreen::OnVisualizeMapping(UI::EventParams ¶ms) { - VisualMappingScreen *visualMapping = new VisualMappingScreen(); + VisualMappingScreen *visualMapping = new VisualMappingScreen(gamePath_); screenManager()->push(visualMapping); return UI::EVENT_DONE; } @@ -328,6 +330,7 @@ void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { std::string pspButtonName = KeyMap::GetPspButtonName(this->pspBtn_); parent->Add(new TextView(std::string(km->T("Map a new key for")) + " " + mc->T(pspButtonName), new LinearLayoutParams(Margins(10,0)))); + SetVRAppMode(VRAppMode::VR_CONTROLLER_MAPPING_MODE); } bool KeyMappingNewKeyDialog::key(const KeyInput &key) { @@ -360,6 +363,7 @@ void KeyMappingNewMouseKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { auto km = GetI18NCategory("KeyMapping"); parent->Add(new TextView(std::string(km->T("You can press ESC to cancel.")), new LinearLayoutParams(Margins(10, 0)))); + SetVRAppMode(VRAppMode::VR_CONTROLLER_MAPPING_MODE); } bool KeyMappingNewMouseKeyDialog::key(const KeyInput &key) { @@ -577,7 +581,7 @@ void JoystickHistoryView::Update() { } } -AnalogSetupScreen::AnalogSetupScreen() { +AnalogSetupScreen::AnalogSetupScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { mapper_.SetCallbacks([](int vkey) {}, [](int vkey) {}, [&](int stick, float x, float y) { analogX_[stick] = x; analogY_[stick] = y; @@ -669,7 +673,7 @@ UI::EventReturn AnalogSetupScreen::OnResetToDefaults(UI::EventParams &e) { } bool TouchTestScreen::touch(const TouchInput &touch) { - UIDialogScreenWithBackground::touch(touch); + UIDialogScreenWithGameBackground::touch(touch); if (touch.flags & TOUCH_DOWN) { bool found = false; for (int i = 0; i < MAX_TOUCH_POINTS; i++) { @@ -798,7 +802,7 @@ bool TouchTestScreen::axis(const AxisInput &axis) { } void TouchTestScreen::render() { - UIDialogScreenWithBackground::render(); + UIDialogScreenWithGameBackground::render(); UIContext *ui_context = screenManager()->getUIContext(); Bounds bounds = ui_context->GetLayoutBounds(); @@ -877,15 +881,25 @@ public: } void Draw(UIContext &dc) override { + for (float dy = 0.0f; dy <= 4.0f; dy += 1.0f) { + for (float dx = 0.0f; dx <= 4.0f; dx += 1.0f) { + if (dx == 2.0f && dy == 2.0f) + continue; + DrawPSP(dc, dx, dy, 0x06C1B6B6); + } + } + DrawPSP(dc, 2.0f, 2.0f, 0xC01C1818); + } + + void DrawPSP(UIContext &dc, float xoff, float yoff, uint32_t color) { using namespace UI; const AtlasImage *whiteImage = dc.Draw()->GetAtlas()->getImage(dc.theme->whiteImage); float centerU = (whiteImage->u1 + whiteImage->u2) * 0.5f; float centerV = (whiteImage->v1 + whiteImage->v2) * 0.5f; - const uint32_t color = 0xB01C1818; auto V = [&](float x, float y) { - dc.Draw()->V(bounds_.x + x * scale_, bounds_.y + y * scale_, color, centerU, centerV); + dc.Draw()->V(bounds_.x + (x + xoff) * scale_, bounds_.y + (y + yoff) * scale_, color, centerU, centerV); }; auto R = [&](float x1, float y1, float x2, float y2) { V(x1, y1); V(x2, y1); V(x2, y2); @@ -928,8 +942,8 @@ public: } void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { - w = 474.0f * scale_; - h = 200.0f * scale_; + w = 478.0f * scale_; + h = 204.0f * scale_; } protected: @@ -1157,7 +1171,7 @@ void VisualMappingScreen::CreateViews() { } void VisualMappingScreen::resized() { - UIDialogScreenWithBackground::resized(); + UIDialogScreenWithGameBackground::resized(); RecreateViews(); } diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index 29f1360fbe..dfb3e81ff5 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -32,9 +32,9 @@ class SingleControlMapper; -class ControlMappingScreen : public UIDialogScreenWithBackground { +class ControlMappingScreen : public UIDialogScreenWithGameBackground { public: - ControlMappingScreen() {} + ControlMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} const char *tag() const override { return "ControlMapping"; } protected: @@ -84,7 +84,7 @@ private: class KeyMappingNewMouseKeyDialog : public PopupScreen { public: - explicit KeyMappingNewMouseKeyDialog(int btn, bool replace, std::function callback, std::shared_ptr i18n) + KeyMappingNewMouseKeyDialog(int btn, bool replace, std::function callback, std::shared_ptr i18n) : PopupScreen(i18n->T("Map Mouse"), "", ""), callback_(callback), mapped_(false) { pspBtn_ = btn; } @@ -109,9 +109,9 @@ private: class JoystickHistoryView; -class AnalogSetupScreen : public UIDialogScreenWithBackground { +class AnalogSetupScreen : public UIDialogScreenWithGameBackground { public: - AnalogSetupScreen(); + AnalogSetupScreen(const Path &gamePath); bool key(const KeyInput &key) override; bool axis(const AxisInput &axis) override; @@ -136,9 +136,9 @@ private: JoystickHistoryView *stickView_[2]{}; }; -class TouchTestScreen : public UIDialogScreenWithBackground { +class TouchTestScreen : public UIDialogScreenWithGameBackground { public: - TouchTestScreen() { + TouchTestScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { for (int i = 0; i < MAX_TOUCH_POINTS; i++) { touches_[i].id = -1; } @@ -175,9 +175,9 @@ protected: class MockPSP; -class VisualMappingScreen : public UIDialogScreenWithBackground { +class VisualMappingScreen : public UIDialogScreenWithGameBackground { public: - VisualMappingScreen() {} + VisualMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} const char *tag() const override { return "VisualMapping"; } diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index dee7a11166..cd6f052ab1 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -35,8 +35,7 @@ static const int FILE_CHECK_FRAME_INTERVAL = 53; CwCheatScreen::CwCheatScreen(const Path &gamePath) - : UIDialogScreenWithBackground() { - gamePath_ = gamePath; + : UIDialogScreenWithGameBackground(gamePath) { } CwCheatScreen::~CwCheatScreen() { @@ -129,7 +128,7 @@ void CwCheatScreen::update() { fileCheckCounter_ = 0; } - UIDialogScreenWithBackground::update(); + UIDialogScreenWithGameBackground::update(); } void CwCheatScreen::onFinish(DialogResult result) { diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index 27a28a1b51..b343cbd818 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -26,7 +26,7 @@ struct CheatFileInfo; class CWCheatEngine; -class CwCheatScreen : public UIDialogScreenWithBackground { +class CwCheatScreen : public UIDialogScreenWithGameBackground { public: CwCheatScreen(const Path &gamePath); ~CwCheatScreen(); @@ -56,7 +56,6 @@ private: UI::ScrollView *rightScroll_ = nullptr; CWCheatEngine *engine_ = nullptr; std::vector fileInfo_; - Path gamePath_; std::string gameID_; int fileCheckCounter_ = 0; uint64_t fileCheckHash_; diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 5dea5e0921..66df64c2ab 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -106,7 +106,8 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { items->Add(new CheckBox(&g_Config.bShowGpuProfile, dev->T("GPU Profile"))); } items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenuScreen::OnFreezeFrame); - items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenuScreen::OnDumpFrame); + + items->Add(new Choice(dev->T("Dump next frame to log")))->OnClick.Handle(this, &DevMenuScreen::OnDumpFrame); items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenuScreen::OnToggleAudioDebug); #ifdef USE_PROFILER items->Add(new CheckBox(&g_Config.bShowFrameProfiler, dev->T("Frame Profiler"), "")); @@ -147,7 +148,7 @@ UI::EventReturn DevMenuScreen::OnLogConfig(UI::EventParams &e) { UI::EventReturn DevMenuScreen::OnDeveloperTools(UI::EventParams &e) { UpdateUIState(UISTATE_PAUSEMENU); - screenManager()->push(new DeveloperToolsScreen()); + screenManager()->push(new DeveloperToolsScreen(gamePath_)); return UI::EVENT_DONE; } @@ -553,6 +554,7 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem(si->T("High precision float range"), temp)); } } + deviceSpecs->Add(new InfoItem(si->T("Depth buffer format"), DataFormatToString(draw->GetDeviceCaps().preferredDepthBufferFormat))); deviceSpecs->Add(new ItemHeader(si->T("OS Information"))); deviceSpecs->Add(new InfoItem(si->T("Memory Page Size"), StringFromFormat(si->T("%d bytes"), GetMemoryProtectPageSize()))); deviceSpecs->Add(new InfoItem(si->T("RW/RX exclusive"), PlatformIsWXExclusive() ? di->T("Active") : di->T("Inactive"))); @@ -567,13 +569,13 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem(si->T("PPSSPP build"), build)); deviceSpecs->Add(new ItemHeader(si->T("Audio Information"))); - deviceSpecs->Add(new InfoItem(si->T("Sample rate"), StringFromFormat("%d Hz", System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE)))); + deviceSpecs->Add(new InfoItem(si->T("Sample rate"), StringFromFormat(si->T("%d Hz"), System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE)))); int framesPerBuffer = System_GetPropertyInt(SYSPROP_AUDIO_FRAMES_PER_BUFFER); if (framesPerBuffer > 0) { deviceSpecs->Add(new InfoItem(si->T("Frames per buffer"), StringFromFormat("%d", framesPerBuffer))); } #if PPSSPP_PLATFORM(ANDROID) - deviceSpecs->Add(new InfoItem(si->T("Optimal sample rate"), StringFromFormat("%d Hz", System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE)))); + deviceSpecs->Add(new InfoItem(si->T("Optimal sample rate"), StringFromFormat(si->T("%d Hz"), System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE)))); deviceSpecs->Add(new InfoItem(si->T("Optimal frames per buffer"), StringFromFormat("%d", System_GetPropertyInt(SYSPROP_AUDIO_OPTIMAL_FRAMES_PER_BUFFER)))); #endif @@ -590,7 +592,7 @@ void SystemInfoScreen::CreateViews() { #if !PPSSPP_PLATFORM(WINDOWS) // Don't show on Windows, since it's always treated as 60 there. - deviceSpecs->Add(new InfoItem(si->T("Refresh rate"), StringFromFormat("%0.3f Hz", (float)System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE)))); + deviceSpecs->Add(new InfoItem(si->T("Refresh rate"), StringFromFormat(si->T("%0.2f Hz"), (float)System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE)))); #endif deviceSpecs->Add(new ItemHeader(si->T("Version Information"))); @@ -617,6 +619,19 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new InfoItem("Moga", moga)); #endif + if (gstate_c.GetUseFlags()) { + // We're in-game, and can determine these. + // TODO: Call a static version of GPUCommon::CheckGPUFeatures() and derive them here directly. + + deviceSpecs->Add(new ItemHeader(si->T("GPU Flags"))); + + for (int i = 0; i < 32; i++) { + if (gstate_c.Use((1 << i))) { + deviceSpecs->Add(new TextView(GpuUseFlagToString(i), new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); + } + } + } + ViewGroup *storageScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); storageScroll->SetTag("DevSystemInfoBuildConfig"); LinearLayout *storage = new LinearLayout(ORIENT_VERTICAL); @@ -1200,7 +1215,7 @@ void ShaderViewScreen::CreateViews() { LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL); root_ = layout; - layout->Add(new TextView(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SHORT_DESC))); + layout->Add(new TextView(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SHORT_DESC), FLAG_DYNAMIC_ASCII | FLAG_WRAP_TEXT, false)); ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0)); scroll->SetTag("DevShaderView"); @@ -1214,7 +1229,7 @@ void ShaderViewScreen::CreateViews() { SplitString(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SOURCE_CODE), '\n', lines); for (auto line : lines) { - lineLayout->Add(new TextView(line, FLAG_DYNAMIC_ASCII, true)); + lineLayout->Add(new TextView(line, FLAG_DYNAMIC_ASCII | FLAG_WRAP_TEXT, true)); } layout->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 0df3d73ce3..687f5e6e11 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -30,7 +30,7 @@ class DevMenuScreen : public PopupScreen { public: - DevMenuScreen(std::shared_ptr i18n) : PopupScreen(i18n->T("Dev Tools")) {} + DevMenuScreen(const Path &gamePath, std::shared_ptr i18n) : PopupScreen(i18n->T("Dev Tools")), gamePath_(gamePath) {} const char *tag() const override { return "DevMenu"; } @@ -47,6 +47,9 @@ protected: UI::EventReturn OnDeveloperTools(UI::EventParams &e); UI::EventReturn OnToggleAudioDebug(UI::EventParams &e); UI::EventReturn OnResetLimitedLogging(UI::EventParams &e); + +private: + Path gamePath_; }; class JitDebugScreen : public UIDialogScreenWithBackground { diff --git a/UI/DisplayLayoutEditor.cpp b/UI/DisplayLayoutEditor.cpp deleted file mode 100644 index f6556ca39a..0000000000 --- a/UI/DisplayLayoutEditor.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include - -#include "Common/UI/Context.h" -#include "UI/DisplayLayoutEditor.h" - -void MultiTouchDisplay::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(img_); - if (image) { - w = image->w * scale_; - h = image->h * scale_; - } else { - w = 0.0f; - h = 0.0f; - } -} - -void MultiTouchDisplay::Touch(const TouchInput &input) { - if ((input.flags & TOUCH_DOWN) && bounds_.Contains(input.x, input.y)) { - pointerDownMask_ |= 1 << input.id; - } - if (input.flags & TOUCH_MOVE) { - if (bounds_.Contains(input.x, input.y)) - pointerDownMask_ |= 1 << input.id; - else - pointerDownMask_ &= ~(1 << input.id); - } - if (input.flags & TOUCH_UP) { - pointerDownMask_ &= ~(1 << input.id); - } - if (input.flags & TOUCH_RELEASE_ALL) { - pointerDownMask_ = 0; - } -} - - -void MultiTouchDisplay::Draw(UIContext &dc) { - float opacity = 0.5f; - float scale = scale_; - uint32_t color = colorAlpha(0xFFFFFF, opacity); - dc.Draw()->DrawImageRotated(img_, bounds_.centerX(), bounds_.centerY(), scale, angle_ * (M_PI * 2 / 360.0f), color, flipImageH_); -} diff --git a/UI/DisplayLayoutEditor.h b/UI/DisplayLayoutEditor.h deleted file mode 100644 index 6855c127ca..0000000000 --- a/UI/DisplayLayoutEditor.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "Common/Render/TextureAtlas.h" -#include "Common/Render/DrawBuffer.h" -#include "Common/UI/View.h" -#include "Common/UI/ViewGroup.h" - -class MultiTouchDisplay : public UI::View { -public: - MultiTouchDisplay(ImageID img, float scale, UI::LayoutParams *layoutParams) - : UI::View(layoutParams), pointerDownMask_(0), scale_(scale), img_(img), angle_(0.0f), flipImageH_(false) { - } - virtual void Touch(const TouchInput &input) override; - virtual void Draw(UIContext &dc) override; - virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; - // chainable - MultiTouchDisplay *FlipImageH(bool flip) { flipImageH_ = flip; return this; } - MultiTouchDisplay *SetAngle(float angle) { angle_ = angle; return this; } - -protected: - uint32_t pointerDownMask_; - float scale_; - -private: - ImageID img_; - float angle_; - bool flipImageH_; -}; - -class PSPDisplay : public MultiTouchDisplay { -public: - PSPDisplay(ImageID img, float scale, UI::LayoutParams *layoutParams) - : MultiTouchDisplay(img, scale, layoutParams) { - } -}; - diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 3e0dd6479a..ab9dd58d86 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -23,6 +23,12 @@ #include "Common/Render/DrawBuffer.h" #include "Common/UI/Context.h" #include "Common/UI/View.h" +#include "Common/UI/UIScreen.h" +#include "Common/Math/math_util.h" +#include "Common/System/Display.h" +#include "Common/System/NativeApp.h" +#include "Common/VR/PPSSPPVR.h" +#include "Common/StringUtils.h" #include "Common/Data/Color/RGBAUtil.h" #include "Common/Data/Text/I18n.h" @@ -30,220 +36,157 @@ #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" -#include "DisplayLayoutEditor.h" #include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Common/PresentationCommon.h" static const int leftColumnWidth = 200; -static const float orgRatio = 1.764706f; +static const float orgRatio = 1.764706f; // 480.0 / 272.0 -static const float UI_DISPLAY_SCALE = 8.0f; -static float ScaleSettingToUI() { - float scale = g_Config.fSmallDisplayZoomLevel * UI_DISPLAY_SCALE; - // Account for 1x display doubling dps. - if (g_dpi_scale_x > 1.0f) { - scale *= g_dpi_scale_x; - } - return scale; +enum Mode { + MODE_INACTIVE = 0, + MODE_MOVE = 1, + MODE_RESIZE = 2, +}; + +static Bounds FRectToBounds(FRect rc) { + Bounds b; + b.x = rc.x * g_dpi_scale_x; + b.y = rc.y * g_dpi_scale_y; + b.w = rc.w * g_dpi_scale_x; + b.h = rc.h * g_dpi_scale_y; + return b; } -static void UpdateScaleSetting(float scale) { - // Account for 1x display doubling dps. - if (g_dpi_scale_x > 1.0f) { - scale /= g_dpi_scale_x; - } - g_Config.fSmallDisplayZoomLevel = scale; -} - -static void UpdateScaleSettingFromUI(float scale) { - UpdateScaleSetting(scale / UI_DISPLAY_SCALE); -} - -class DragDropDisplay : public MultiTouchDisplay { +class DisplayLayoutBackground : public UI::View { public: - DragDropDisplay(float &x, float &y, ImageID img, float scale, const Bounds &screenBounds) - : MultiTouchDisplay(img, scale, new UI::AnchorLayoutParams(x * screenBounds.w, y * screenBounds.h, UI::NONE, UI::NONE, true)), - x_(x), y_(y), screenBounds_(screenBounds) { - UpdateScale(scale); - } + DisplayLayoutBackground(UI::ChoiceStrip *mode, UI::LayoutParams *layoutParams) : UI::View(layoutParams), mode_(mode) {} - std::string DescribeText() const override; + bool Touch(const TouchInput &touch) override { + int mode = mode_ ? mode_->GetSelection() : 0; - void SaveDisplayPosition() { - x_ = bounds_.centerX() / screenBounds_.w; - y_ = bounds_.centerY() / screenBounds_.h; - } + if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { + float relativeTouchX = touch.x - startX_; + float relativeTouchY = touch.y - startY_; - void UpdateScale(float s) { - scale_ = s; - } - float Scale() { - return scale_; + switch (mode) { + case MODE_MOVE: + g_Config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / bounds_.w, 0.0f, 1.0f); + g_Config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / bounds_.h, 0.0f, 1.0f); + break; + case MODE_RESIZE: + { + // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction + float diffYProp = -relativeTouchY * 0.007f; + g_Config.fDisplayScale = clamp_value(startScale_ * powf(2.0f, diffYProp), 0.2f, 2.0f); + break; + } + } + } + + if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) { + // Check that we're in the central 80% of the screen. + // If outside, it may be a drag from displaying the back button on phones + // where you have to drag from the side, etc. + if (touch.x >= bounds_.w * 0.1f && touch.x <= bounds_.w * 0.9f && + touch.y >= bounds_.h * 0.1f && touch.y <= bounds_.h * 0.9f) { + dragging_ = true; + startX_ = touch.x; + startY_ = touch.y; + startDisplayOffsetX_ = g_Config.fDisplayOffsetX; + startDisplayOffsetY_ = g_Config.fDisplayOffsetY; + startScale_ = g_Config.fDisplayScale; + } + } + + if ((touch.flags & TOUCH_UP) != 0 && dragging_) { + dragging_ = false; + } + + return true; } private: - float &x_, &y_; - const Bounds &screenBounds_; + UI::ChoiceStrip *mode_; + bool dragging_ = false; + + // Touch down state for drag to resize etc + float startX_ = 0.0f; + float startY_ = 0.0f; + float startScale_ = -1.0f; + float startDisplayOffsetX_ = -1.0f; + float startDisplayOffsetY_ = -1.0f; }; -std::string DragDropDisplay::DescribeText() const { - auto u = GetI18NCategory("UI Elements"); - return u->T("Screen representation"); +DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) { + // Show background at full brightness + darkenGameBackground_ = false; } -DisplayLayoutScreen::DisplayLayoutScreen() { - // Ignore insets - just couldn't get the logic to work. - ignoreInsets_ = true; -} +void DisplayLayoutScreen::DrawBackground(UIContext &dc) { + if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { + // We normally rely on the PSP screen. + UIDialogScreenWithGameBackground::DrawBackground(dc); + } else { + // But if it's not present (we're not in game, or skip buffer effects is used), + // we have to draw a substitute ourselves. -bool DisplayLayoutScreen::touch(const TouchInput &touch) { - UIScreen::touch(touch); + // TODO: Clean this up a bit, this GetScreenFrame/CenterDisplay combo is too common. + FRect screenFrame = GetScreenFrame(pixel_xres, pixel_yres); + FRect rc; + CenterDisplayOutputRect(&rc, 480.0f, 272.0f, screenFrame, g_Config.iInternalScreenRotation); - using namespace UI; - - int mode = mode_ ? mode_->GetSelection() : 0; - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - mode = -1; + dc.Flush(); + ImageID bg = ImageID("I_PSP_DISPLAY"); + dc.Draw()->DrawImageStretch(bg, FRectToBounds(rc), 0x7FFFFFFF); } - - const Bounds &screen_bounds = screenManager()->getUIContext()->GetBounds(); - if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { - int touchX = touch.x - offsetTouchX_; - int touchY = touch.y - offsetTouchY_; - if (mode == 0) { - const auto &prevParams = displayRepresentation_->GetLayoutParams()->As(); - Point newPos(prevParams->left, prevParams->top); - - int limitX = g_Config.fSmallDisplayZoomLevel * 120; - int limitY = g_Config.fSmallDisplayZoomLevel * 68; - - const int quarterResX = screen_bounds.w / 4; - const int quarterResY = screen_bounds.h / 4; - - if (bRotated_) { - //swap X/Y limit for rotated display - std::swap(limitX, limitY); - } - - // Check where each edge of the screen is - const int windowLeftEdge = quarterResX; - const int windowRightEdge = windowLeftEdge * 3; - const int windowUpperEdge = quarterResY; - const int windowLowerEdge = windowUpperEdge * 3; - // And stick display when close to any edge - stickToEdgeX_ = false; - stickToEdgeY_ = false; - if (touchX > windowLeftEdge - 8 + limitX && touchX < windowLeftEdge + 8 + limitX) { touchX = windowLeftEdge + limitX; stickToEdgeX_ = true; } - if (touchX > windowRightEdge - 8 - limitX && touchX < windowRightEdge + 8 - limitX) { touchX = windowRightEdge - limitX; stickToEdgeX_ = true; } - if (touchY > windowUpperEdge - 8 + limitY && touchY < windowUpperEdge + 8 + limitY) { touchY = windowUpperEdge + limitY; stickToEdgeY_ = true; } - if (touchY > windowLowerEdge - 8 - limitY && touchY < windowLowerEdge + 8 - limitY) { touchY = windowLowerEdge - limitY; stickToEdgeY_ = true; } - - const int minX = screen_bounds.w / 2; - const int maxX = screen_bounds.w + minX; - const int minY = screen_bounds.h / 2; - const int maxY = screen_bounds.h + minY; - // Display visualization disappear outside of those bounds, so we have to limit - if (touchX < -minX) touchX = -minX; - if (touchX > maxX) touchX = maxX; - if (touchY < -minY) touchY = -minY; - if (touchY > maxY) touchY = maxY; - - // Limit small display on much larger output a bit differently - if (quarterResX > limitX) limitX = quarterResX; - if (quarterResY > limitY) limitY = quarterResY; - - // Allow moving zoomed in display freely as long as at least noticeable portion of the screen is occupied - if (touchX > minX - limitX - 10 && touchX < minX + limitX + 10) { - newPos.x = touchX; - } - if (touchY > minY - limitY - 10 && touchY < minY + limitY + 10) { - newPos.y = touchY; - } - displayRepresentation_->ReplaceLayoutParams(new AnchorLayoutParams(newPos.x, newPos.y, NONE, NONE, true)); - } else if (mode == 1) { - // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction - float diffY = -(touchY - startY_); - - float movementScale = 0.5f; - float newScale = startScale_ + diffY * movementScale; - // Desired scale * 8.0 since the visualization is tiny size and multiplied by 8. - newScale = clamp_value(newScale, UI_DISPLAY_SCALE, UI_DISPLAY_SCALE * 10.0f); - displayRepresentation_->UpdateScale(newScale); - UpdateScaleSettingFromUI(newScale); - } - } - if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) { - dragging_ = true; - const Bounds &bounds = displayRepresentation_->GetBounds(); - startY_ = bounds.centerY(); - offsetTouchX_ = touch.x - bounds.centerX(); - offsetTouchY_ = touch.y - bounds.centerY(); - startScale_ = displayRepresentation_->Scale(); - } - if ((touch.flags & TOUCH_UP) != 0 && dragging_) { - displayRepresentation_->SaveDisplayPosition(); - dragging_ = false; - } - return true; -} - -void DisplayLayoutScreen::resized() { - RecreateViews(); } void DisplayLayoutScreen::onFinish(DialogResult reason) { g_Config.Save("DisplayLayoutScreen::onFinish"); } -UI::EventReturn DisplayLayoutScreen::OnCenter(UI::EventParams &e) { - if (!stickToEdgeX_ || (stickToEdgeX_ && stickToEdgeY_)) - g_Config.fSmallDisplayOffsetX = 0.5f; - if (!stickToEdgeY_ || (stickToEdgeX_ && stickToEdgeY_)) - g_Config.fSmallDisplayOffsetY = 0.5f; - RecreateViews(); - return UI::EVENT_DONE; -}; - -UI::EventReturn DisplayLayoutScreen::OnZoomTypeChange(UI::EventParams &e) { - if (g_Config.iSmallDisplayZoomType < (int)SmallDisplayZoom::MANUAL) { - const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); - float autoBound = bounds.w / 480.0f; - UpdateScaleSetting(autoBound); - displayRepresentation_->UpdateScale(ScaleSettingToUI()); - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - } - RecreateViews(); - return UI::EVENT_DONE; -}; - void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) { RecreateViews(); } -class Boundary : public UI::View { -public: - Boundary(UI::LayoutParams *layoutParams) : UI::View(layoutParams) { +UI::EventReturn DisplayLayoutScreen::OnPostProcShaderChange(UI::EventParams &e) { + // Remove the virtual "Off" entry. TODO: Get rid of it generally. + g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); + FixPostShaderOrder(&g_Config.vPostShaderNames); + + NativeMessageReceived("gpu_configChanged", ""); + NativeMessageReceived("gpu_renderResized", ""); // To deal with shaders that can change render resolution like upscaling. + NativeMessageReceived("postshader_updated", ""); + + if (gpu) { + gpu->NotifyConfigChanged(); + } + return UI::EVENT_DONE; +} + +static std::string PostShaderTranslateName(const char *value) { + auto gr = GetI18NCategory("Graphics"); + auto ps = GetI18NCategory("PostShaders"); + if (!strcmp(value, "Off")) { + // Off is a legacy fake item (gonna migrate off it later). + return gr->T("Add postprocessing shader"); } - std::string DescribeText() const override { - return ""; + const ShaderInfo *info = GetPostShaderInfo(value); + if (info) { + return ps->T(value, info ? info->name.c_str() : value); + } else { + return value; } +} - void Draw(UIContext &dc) override { - dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), dc.theme->itemDownStyle.background.color); +void DisplayLayoutScreen::sendMessage(const char *message, const char *value) { + UIDialogScreenWithGameBackground::sendMessage(message, value); + if (!strcmp(message, "postshader_updated")) { + g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); + RecreateViews(); } -}; - -// Stealing StickyChoice's layout and text rendering. -class HighlightLabel : public UI::StickyChoice { -public: - HighlightLabel(const std::string &text, UI::LayoutParams *layoutParams) - : UI::StickyChoice(text, "", layoutParams) { - Press(); - } - - bool CanBeFocused() const override { return false; } -}; +} void DisplayLayoutScreen::CreateViews() { const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); @@ -253,129 +196,296 @@ void DisplayLayoutScreen::CreateViews() { auto di = GetI18NCategory("Dialog"); auto gr = GetI18NCategory("Graphics"); auto co = GetI18NCategory("Controls"); + auto ps = GetI18NCategory("PostShaders"); root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - const float previewWidth = bounds.w / 2.0f; - const float previewHeight = bounds.h / 2.0f; + bool vertical = bounds.h > bounds.w; - // Just visual boundaries of the screen, should be easier to use than imagination - const float horizPreviewPadding = bounds.w / 4.0f; - const float vertPreviewPadding = bounds.h / 4.0f; - const float horizBoundariesWidth = 4.0f; - // This makes it have at least 10.0f padding below at 1x. - const float vertBoundariesHeight = 52.0f; + // Make it so that a touch can only affect one view. Makes manipulating the background through the buttons + // impossible. + root_->SetExclusiveTouch(true); - // We manually implement insets here for the buttons. This file defied refactoring :( - float leftInset = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT); - - // Left side, right, top, bottom. - root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, horizPreviewPadding - horizBoundariesWidth, 0, NONE, 0))); - root_->Add(new Boundary(new AnchorLayoutParams(horizBoundariesWidth, FILL_PARENT, horizPreviewPadding + previewWidth, 0, NONE, 0))); - root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding - vertBoundariesHeight, NONE, NONE))); - root_->Add(new Boundary(new AnchorLayoutParams(previewWidth, vertBoundariesHeight, horizPreviewPadding, vertPreviewPadding + previewHeight, NONE, NONE))); - - bool displayRotEnable = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) || g_Config.bSoftwareRendering; - bRotated_ = false; - if (displayRotEnable && (g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || g_Config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180)) { - bRotated_ = true; + LinearLayout *leftColumn; + if (!vertical) { + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(420.0f, FILL_PARENT, 0.f, 0.f, NONE, 0.f, false)); + leftColumn = new LinearLayout(ORIENT_VERTICAL); + leftColumn->padding.SetAll(8.0f); + leftScrollView->Add(leftColumn); + leftScrollView->SetClickableBackground(true); + root_->Add(leftScrollView); } - HighlightLabel *label = nullptr; - mode_ = nullptr; - if (g_Config.iSmallDisplayZoomType >= (int)SmallDisplayZoom::AUTO) { // Scaling - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - label = new HighlightLabel(gr->T("Auto Scaling"), new AnchorLayoutParams(WRAP_CONTENT, 64.0f, bounds.w / 2.0f, bounds.h / 2.0f, NONE, NONE, true)); - float autoBound = bounds.h / 270.0f; - // Case of screen rotated ~ only works with buffered rendering - if (bRotated_) { - autoBound = bounds.h / 480.0f; - } else { // Without rotation in common cases like 1080p we cut off 2 pixels of height, this reflects other cases - float resCommonWidescreen = autoBound - floor(autoBound); - if (resCommonWidescreen != 0.0f) { - float ratio = bounds.w / bounds.h; - if (ratio < orgRatio) { - autoBound = bounds.w / 480.0f; - } - else { - autoBound = bounds.h / 272.0f; - } - } - } - UpdateScaleSetting(autoBound); - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - } else { // Manual Scaling - Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); - center->OnClick.Handle(this, &DisplayLayoutScreen::OnCenter); - root_->Add(center); - float minZoom = 1.0f; - if (g_dpi_scale_x > 1.0f) { - minZoom /= g_dpi_scale_x; - } - PopupSliderChoiceFloat *zoomlvl = new PopupSliderChoiceFloat(&g_Config.fSmallDisplayZoomLevel, minZoom, 10.0f, di->T("Zoom"), 1.0f, screenManager(), di->T("* PSP res"), new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); - root_->Add(zoomlvl); - mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); - mode_->AddChoice(di->T("Move")); - mode_->AddChoice(di->T("Resize")); - mode_->SetSelection(0, false); - } - displayRepresentation_ = new DragDropDisplay(g_Config.fSmallDisplayOffsetX, g_Config.fSmallDisplayOffsetY, ImageID("I_PSP_DISPLAY"), ScaleSettingToUI(), bounds); - displayRepresentation_->SetVisibility(V_VISIBLE); - } else { // Stretching - label = new HighlightLabel(gr->T("Stretching"), new AnchorLayoutParams(WRAP_CONTENT, 64.0f, bounds.w / 2.0f, bounds.h / 2.0f, NONE, NONE, true)); - displayRepresentation_ = new DragDropDisplay(g_Config.fSmallDisplayOffsetX, g_Config.fSmallDisplayOffsetY, ImageID("I_PSP_DISPLAY"), ScaleSettingToUI(), bounds); - displayRepresentation_->SetVisibility(V_INVISIBLE); - float width = previewWidth; - float height = previewHeight; - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::STRETCH) { - Choice *stretched = new Choice("", "", false, new AnchorLayoutParams(width, height, width - width / 2.0f, NONE, NONE, height - height / 2.0f)); - stretched->SetEnabled(false); - root_->Add(stretched); - } else { // Partially stretched - float origRatio = !bRotated_ ? 480.0f / 272.0f : 272.0f / 480.0f; - float frameRatio = width / height; - if (origRatio > frameRatio) { - height = width / origRatio; - if (!bRotated_ && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) { - height = (272.0f + height) / 2.0f; - } - } else { - width = height * origRatio; - if (bRotated_ && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH) { - width = (272.0f + height) / 2.0f; - } - } - Choice *stretched = new Choice("", "", false, new AnchorLayoutParams(width, height, previewWidth - width / 2.0f, NONE, NONE, previewHeight - height / 2.0f)); - stretched->SetEnabled(false); - root_->Add(stretched); - } - } - if (bRotated_) { - displayRepresentation_->SetAngle(90.0f); + ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 0.f, 0.f, 0.f, false)); + LinearLayout *rightColumn = new LinearLayout(ORIENT_VERTICAL); + rightColumn->padding.SetAll(8.0f); + rightScrollView->Add(rightColumn); + rightScrollView->SetClickableBackground(true); + root_->Add(rightScrollView); + + LinearLayout *bottomControls; + if (vertical) { + bottomControls = new LinearLayout(ORIENT_HORIZONTAL); + rightColumn->Add(bottomControls); + leftColumn = rightColumn; + } else { + bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f, false)); + root_->Add(bottomControls); } - root_->Add(displayRepresentation_); - if (mode_) { - root_->Add(mode_); - } - if (label) { - root_->Add(label); + // Set backgrounds for readability + Drawable backgroundWithAlpha(GetBackgroundColorWithAlpha(*screenManager()->getUIContext())); + leftColumn->SetBG(backgroundWithAlpha); + rightColumn->SetBG(backgroundWithAlpha); + + if (!IsVREnabled()) { + auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch")); + rightColumn->Add(stretch); + + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, gr->T("Aspect Ratio"), screenManager()); + rightColumn->Add(aspectRatio); + aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch); + aspectRatio->SetHasDropShadow(false); + aspectRatio->SetLiveUpdate(true); + + mode_ = new ChoiceStrip(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + mode_->AddChoice(di->T("Inactive")); + mode_->AddChoice(di->T("Move")); + mode_->AddChoice(di->T("Resize")); + mode_->SetSelection(0, false); + bottomControls->Add(mode_); + + static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; + auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); + rotation->SetEnabledFunc([] { + return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; + }); + rightColumn->Add(rotation); + + Choice *center = new Choice(di->T("Reset")); + center->OnClick.Add([&](UI::EventParams &) { + g_Config.fDisplayAspectRatio = 1.0f; + g_Config.fDisplayScale = 1.0f; + g_Config.fDisplayOffsetX = 0.5f; + g_Config.fDisplayOffsetY = 0.5f; + return UI::EVENT_DONE; + }); + rightColumn->Add(center); + + rightColumn->Add(new Spacer(12.0f)); } - static const char *zoomLevels[] = { "Stretching", "Partial Stretch", "Auto Scaling", "Manual Scaling" }; - auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, di->T("Options"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, previewWidth - 200.0f, NONE, NONE, 10)); - zoom->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomTypeChange); - root_->Add(zoom); - - static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; - auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, previewWidth - 200.0f, 10, NONE, bounds.h - 64 - 10)); - rotation->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE || g_Config.bSoftwareRendering; - }); - root_->Add(rotation); - - Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10)); + Choice *back = new Choice(di->T("Back"), "", false); back->OnClick.Handle(this, &UIScreen::OnBack); - root_->Add(back); + rightColumn->Add(back); + + if (vertical) { + leftColumn->Add(new Spacer(24.0f)); + } + + static const char *bufFilters[] = { "Linear", "Nearest", }; + leftColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); + + Draw::DrawContext *draw = screenManager()->getDrawContext(); + + bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; + + auto enableStereo = [=]() -> bool { + return g_Config.bStereoRendering && multiViewSupported; + }; + + leftColumn->Add(new ItemHeader(gr->T("Postprocessing shaders"))); + + std::set alreadyAddedShader; + // If there's a single post shader and we're just entering the dialog, + // auto-open the settings. + if (settingsVisible_.empty() && g_Config.vPostShaderNames.size() == 1) { + settingsVisible_.push_back(true); + } else if (settingsVisible_.size() < g_Config.vPostShaderNames.size()) { + settingsVisible_.resize(g_Config.vPostShaderNames.size()); + } + + static ContextMenuItem postShaderContextMenu[] = { + { "Move Up", "I_ARROW_UP" }, + { "Move Down", "I_ARROW_DOWN" }, + { "Remove", "I_TRASHCAN" }, + }; + + for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { + // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread + shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; + + LinearLayout *shaderRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)); + shaderRow->SetSpacing(4.0f); + leftColumn->Add(shaderRow); + + if (shaderNames_[i] != "Off") { + postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); + } else { + postProcChoice_ = shaderRow->Add(new Choice(ImageID("I_PLUS"))); + } + postProcChoice_->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Postprocessing shaders"), i, false); + procScreen->SetHasDropShadow(false); + procScreen->OnChoice.Handle(this, &DisplayLayoutScreen::OnPostProcShaderChange); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + postProcChoice_->SetEnabledFunc([=] { + return !g_Config.bSkipBufferEffects && !enableStereo(); + }); + + if (i < g_Config.vPostShaderNames.size()) { + bool hasSettings = false; + std::vector shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + hasSettings = true; + break; + } + } + } + if (hasSettings) { + CheckBox *checkBox = new CheckBox(&settingsVisible_[i], ImageID("I_SLIDERS"), new LinearLayoutParams(0.0f)); + auto settingsButton = shaderRow->Add(checkBox); + settingsButton->OnClick.Add([=](EventParams &e) { + RecreateViews(); + return UI::EVENT_DONE; + }); + } + + auto removeButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(0.0f))); + removeButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { + g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); + NativeMessageReceived("gpu_configChanged", ""); + RecreateViews(); + return UI::EVENT_DONE; + }); + + auto moreButton = shaderRow->Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(0.0f))); + moreButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { + PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), di.get(), moreButton); + screenManager()->push(contextMenu); + const ShaderInfo *info = GetPostShaderInfo(g_Config.vPostShaderNames[i]); + bool usesLastFrame = info ? info->usePreviousFrame : false; + contextMenu->SetEnabled(0, i > 0 && !usesLastFrame); + contextMenu->SetEnabled(1, i < g_Config.vPostShaderNames.size() - 1); + contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn { + switch (e.a) { + case 0: // Move up + std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); + break; + case 1: // Move down + std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); + break; + case 2: // Remove + g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); + break; + default: + return UI::EVENT_DONE; + } + FixPostShaderOrder(&g_Config.vPostShaderNames); + NativeMessageReceived("gpu_configChanged", ""); + RecreateViews(); + return UI::EVENT_DONE; + }); + return UI::EVENT_DONE; + }); + } + + + // No need for settings on the last one. + if (i == g_Config.vPostShaderNames.size()) + continue; + + if (!settingsVisible_[i]) + continue; + + std::vector shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + // Disable duplicated shader slider + bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); + alreadyAddedShader.insert(shaderInfo->section); + + LinearLayout *settingContainer = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT, UI::Margins(24.0f, 0.0f, 0.0f, 0.0f))); + leftColumn->Add(settingContainer); + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + // This map lookup will create the setting in the mPostShaderSetting map if it doesn't exist, with a default value of 0.0. + std::string key = StringFromFormat("%sSettingCurrentValue%d", shaderInfo->section.c_str(), i + 1); + bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end(); + auto &value = g_Config.mPostShaderSetting[key]; + if (!keyExisted) + value = setting.value; + + if (duplicated) { + auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); + PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); + settingValue->SetEnabled(false); + } else { + PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetLiveUpdate(true); + settingValue->SetHasDropShadow(false); + settingValue->SetEnabledFunc([=] { + return !g_Config.bSkipBufferEffects && !enableStereo(); + }); + } + } + } + } + } + + root_->Add(new DisplayLayoutBackground(mode_, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f))); +} + +void PostProcScreen::CreateViews() { + auto ps = GetI18NCategory("PostShaders"); + ReloadAllPostShaderInfo(screenManager()->getDrawContext()); + shaders_ = GetAllPostShaderInfo(); + std::vector items; + int selected = -1; + const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; + + for (int i = 0; i < (int)shaders_.size(); i++) { + if (!shaders_[i].visible) + continue; + if (shaders_[i].isStereo != showStereoShaders_) + continue; + if (shaders_[i].section == selectedName) + selected = (int)indexTranslation_.size(); + items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); + indexTranslation_.push_back(i); + } + adaptor_ = UI::StringVectorListAdaptor(items, selected); + ListPopupScreen::CreateViews(); +} + +void PostProcScreen::OnCompleted(DialogResult result) { + if (result != DR_OK) + return; + const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section; + // I feel this logic belongs more in the caller, but eh... + if (showStereoShaders_) { + if (g_Config.sStereoToMonoShader != value) { + g_Config.sStereoToMonoShader = value; + NativeMessageReceived("gpu_configChanged", ""); + } + } else { + if (id_ < (int)g_Config.vPostShaderNames.size()) { + if (g_Config.vPostShaderNames[id_] != value) { + g_Config.vPostShaderNames[id_] = value; + NativeMessageReceived("gpu_configChanged", ""); + } + } + else { + g_Config.vPostShaderNames.push_back(value); + NativeMessageReceived("gpu_configChanged", ""); + } + } } diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 06730742d4..a494b9d288 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -17,37 +17,55 @@ #pragma once +#include + #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "GPU/Common/PostShader.h" + #include "MiscScreens.h" -class DragDropDisplay; - -class DisplayLayoutScreen : public UIDialogScreenWithBackground { +class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { public: - DisplayLayoutScreen(); - virtual void CreateViews() override; - virtual bool touch(const TouchInput &touch) override; - virtual void dialogFinished(const Screen *dialog, DialogResult result) override; - virtual void onFinish(DialogResult reason) override; - virtual void resized() override; + DisplayLayoutScreen(const Path &filename); + void CreateViews() override; + void dialogFinished(const Screen *dialog, DialogResult result) override; + void onFinish(DialogResult reason) override; + + void DrawBackground(UIContext &dc) override; + + void resized() override { + RecreateViews(); + } + const char *tag() const override { return "DisplayLayout"; } protected: - virtual UI::EventReturn OnCenter(UI::EventParams &e); - virtual UI::EventReturn OnZoomTypeChange(UI::EventParams &e); + UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); + + void sendMessage(const char *message, const char *value) override; private: - DragDropDisplay *displayRepresentation_ = nullptr; UI::ChoiceStrip *mode_ = nullptr; - bool dragging_ = false; - bool bRotated_ = false; - bool stickToEdgeX_ = false; - bool stickToEdgeY_ = false; - // Touch down state for drag to resize etc - float startY_ = 0.0f; - float startScale_ = 1.0f; - int offsetTouchX_ = 0; - int offsetTouchY_ = 0; - + UI::Choice *postProcChoice_ = nullptr; + std::string shaderNames_[256]; + std::deque settingsVisible_; // vector is an insane bitpacked specialization! +}; + +class PostProcScreen : public ListPopupScreen { +public: + PostProcScreen(const std::string &title, int id, bool showStereoShaders) + : ListPopupScreen(title), id_(id), showStereoShaders_(showStereoShaders) { } + + void CreateViews() override; + + const char *tag() const override { return "PostProc"; } + +private: + void OnCompleted(DialogResult result) override; + bool ShowButtons() const override { return true; } + std::vector shaders_; + int id_; + bool showStereoShaders_; + std::vector indexTranslation_; }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bcf5a47a48..e3e8a6dcfa 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -31,6 +31,8 @@ using namespace std::placeholders; #include "Common/UI/Context.h" #include "Common/UI/Tween.h" #include "Common/UI/View.h" +#include "Common/UI/AsyncImageFileView.h" +#include "Common/VR/PPSSPPVR.h" #include "Common/Data/Text/I18n.h" #include "Common/Input/InputState.h" @@ -134,8 +136,6 @@ static void __EmuScreenVblank() } // Handles control rotation due to internal screen rotation. -// TODO: This should be a callback too, so we don't actually call the __Ctrl functions -// from settings screens, etc. static void SetPSPAnalog(int stick, float x, float y) { switch (g_Config.iInternalScreenRotation) { case ROTATION_LOCKED_HORIZONTAL: @@ -162,7 +162,6 @@ static void SetPSPAnalog(int stick, float x, float y) { default: break; } - __CtrlSetAnalogXY(stick, x, y); } @@ -327,12 +326,12 @@ void EmuScreen::bootGame(const Path &filename) { System_SendMessage("event", "failstartgame"); } - if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { + if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.bSkipBufferEffects) { auto gr = GetI18NCategory("Graphics"); host->NotifyUserMessage(gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 15.0f); } - if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bBlockTransferGPU == false) { + if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bSkipGPUReadbacks) { auto gr = GetI18NCategory("Graphics"); host->NotifyUserMessage(gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 15.0f); } @@ -484,10 +483,10 @@ void EmuScreen::sendMessage(const char *message, const char *value) { RecreateViews(); } else if (!strcmp(message, "control mapping") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - screenManager()->push(new ControlMappingScreen()); + screenManager()->push(new ControlMappingScreen(gamePath_)); } else if (!strcmp(message, "display layout editor") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - screenManager()->push(new DisplayLayoutScreen()); + screenManager()->push(new DisplayLayoutScreen(gamePath_)); } else if (!strcmp(message, "settings") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); screenManager()->push(new GameSettingsScreen(gamePath_)); @@ -659,7 +658,7 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { if (g_Config.bDumpFrames == g_Config.bDumpAudio) { g_Config.bDumpFrames = !g_Config.bDumpFrames; g_Config.bDumpAudio = !g_Config.bDumpAudio; - } else { + } else { // This hotkey should always toggle both audio and video together. // So let's make sure that's the only outcome even if video OR audio was already being dumped. if (g_Config.bDumpFrames) { @@ -704,7 +703,7 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { g_Config.bSaveNewTextures = !g_Config.bSaveNewTextures; if (g_Config.bSaveNewTextures) { osm.Show(sc->T("saveNewTextures_true", "Textures will now be saved to your storage"), 2.0); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } else { osm.Show(sc->T("saveNewTextures_false", "Texture saving was disabled"), 2.0); } @@ -715,7 +714,7 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { osm.Show(sc->T("replaceTextures_true", "Texture replacement enabled"), 2.0); else osm.Show(sc->T("replaceTextures_false", "Textures no longer are being replaced"), 2.0); - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); break; case VIRTKEY_RAPID_FIRE: __CtrlSetRapidFire(true); @@ -966,7 +965,7 @@ void EmuScreen::CreateViews() { UI::EventReturn EmuScreen::OnDevTools(UI::EventParams ¶ms) { auto dev = GetI18NCategory("Developer"); - DevMenuScreen *devMenu = new DevMenuScreen(dev); + DevMenuScreen *devMenu = new DevMenuScreen(gamePath_, dev); if (params.v) devMenu->SetPopupOrigin(params.v); screenManager()->push(devMenu); @@ -1059,7 +1058,7 @@ void EmuScreen::update() { errLoadingFile.append(" "); errLoadingFile.append(err->T(errorMessage_.c_str())); - screenManager()->push(new PromptScreen(errLoadingFile, "OK", "")); + screenManager()->push(new PromptScreen(gamePath_, errLoadingFile, "OK", "")); errorMessage_.clear(); quit_ = true; return; @@ -1104,7 +1103,6 @@ void EmuScreen::update() { } } } - } void EmuScreen::checkPowerDown() { @@ -1355,8 +1353,7 @@ void EmuScreen::preRender() { // We only bind it in FramebufferManager::CopyDisplayToOutput (unless non-buffered)... // We do, however, start the frame in other ways. - bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) { + if ((g_Config.bSkipBufferEffects && !g_Config.bSoftwareRendering) || Core_IsStepping()) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer"); @@ -1475,6 +1472,12 @@ void EmuScreen::render() { screenManager()->getUIContext()->BeginFrame(); renderUI(); } + + if (chatMenu_ && (chatMenu_->GetVisibility() == UI::V_VISIBLE)) { + SetVRAppMode(VRAppMode::VR_DIALOG_MODE); + } else { + SetVRAppMode(screenManager()->topScreen() == this ? VRAppMode::VR_GAME_MODE : VRAppMode::VR_DIALOG_MODE); + } } bool EmuScreen::hasVisibleUI() { diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 023b9e1def..ab0a11d300 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -44,7 +44,7 @@ static const std::vector fsDiscard = { layout(location = 0) in vec4 oColor0; layout(location = 1) in vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; - layout(set = 0, binding = 1) uniform sampler2D Sampler0; + layout(set = 1, binding = 1) uniform sampler2D Sampler0; void main() { vec4 color = texture(Sampler0, oTexCoord0) * oColor0; if (color.a <= 0.0) @@ -86,7 +86,7 @@ static const std::vector fsAdrenoLogicTest = { layout(location = 0) in vec4 oColor0; layout(location = 1) in highp vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; - layout(set = 0, binding = 1) uniform sampler2D Sampler0; + layout(set = 1, binding = 1) uniform sampler2D Sampler0; void main() { vec4 v = texture(Sampler0, oTexCoord0).aaaa * oColor0; if (v.r < 0.2 && v.g < 0.2 && v.b < 0.2) discard; @@ -117,7 +117,7 @@ static const std::vector vsAdrenoLogicTest = { "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" - "layout (std140, set = 0, binding = 0) uniform bufferVals {\n" + "layout (std140, set = 1, binding = 0) uniform bufferVals {\n" " mat4 WorldViewProj;\n" "} myBufferVals;\n" "layout (location = 0) in vec4 pos;\n" @@ -173,7 +173,7 @@ static const std::vector fsFlat = { "layout(location = 0) flat in lowp vec4 oColor0;\n" "layout(location = 1) in highp vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0;\n" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n" } }; @@ -214,7 +214,7 @@ static const std::vector vsFlat = { "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" - "layout (std140, set = 0, binding = 0) uniform bufferVals {\n" + "layout (std140, set = 1, binding = 0) uniform bufferVals {\n" " mat4 WorldViewProj;\n" "} myBufferVals;\n" "layout (location = 0) in vec4 pos;\n" diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index ec4ea77700..16efa42e90 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -29,6 +29,7 @@ #include "Common/File/Path.h" #include "Common/StringUtils.h" #include "Common/TimeUtil.h" +#include "Common/Render/ManagedTexture.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/FileSystems/DirectoryFileSystem.h" #include "Core/FileSystems/VirtualDiscFileSystem.h" @@ -39,7 +40,6 @@ #include "Core/Util/GameManager.h" #include "Core/Config.h" #include "UI/GameInfoCache.h" -#include "UI/TextureUtil.h" GameInfoCache *g_gameInfoCache; @@ -334,7 +334,7 @@ public: : gamePath_(gamePath), info_(info) { } - ~GameInfoWorkItem() override { + ~GameInfoWorkItem() { info_->pending.store(false); info_->working.store(false); info_->DisposeFileLoader(); diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index a23aa92442..1df4f64ad5 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -26,7 +26,7 @@ #include "Common/Thread/Event.h" #include "Core/ELF/ParamSFO.h" #include "Common/File/Path.h" -#include "UI/TextureUtil.h" +#include "Common/Render/ManagedTexture.h" namespace Draw { class DrawContext; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index edf519f46b..33773e5adb 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -43,6 +43,7 @@ #include "UI/MiscScreens.h" #include "UI/MainScreen.h" #include "UI/BackgroundAudio.h" +#include "UI/SavedataScreen.h" #include "Core/Reporting.h" GameScreen::GameScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { @@ -242,7 +243,7 @@ UI::EventReturn GameScreen::OnDeleteConfig(UI::EventParams &e) auto di = GetI18NCategory("Dialog"); auto ga = GetI18NCategory("Game"); screenManager()->push( - new PromptScreen(di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteConfig, this, std::placeholders::_1))); return UI::EVENT_DONE; @@ -373,7 +374,7 @@ UI::EventReturn GameScreen::OnDeleteSaveData(UI::EventParams &e) { // Check that there's any savedata to delete if (saveDirs.size()) { screenManager()->push( - new PromptScreen(di->T("DeleteConfirmAll", "Do you really want to delete all\nyour save data for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmAll", "Do you really want to delete all\nyour save data for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteSaveData, this, std::placeholders::_1))); } } @@ -397,7 +398,7 @@ UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) { std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); if (info) { screenManager()->push( - new PromptScreen(di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteGame, this, std::placeholders::_1))); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 153f03d69c..32c71aedf9 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -92,15 +92,10 @@ extern AndroidAudioState *g_audioState; GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) { - lastVertical_ = UseVerticalLayout(); prevInflightFrames_ = g_Config.iInflightFrames; analogSpeedMapped_ = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr); } -bool GameSettingsScreen::UseVerticalLayout() const { - return dp_yres > dp_xres * 1.1f; -} - // This needs before run CheckGPUFeatures() // TODO: Remove this if fix the issue bool CheckSupportShaderTessellationGLES() { @@ -136,20 +131,10 @@ static bool UsingHardwareTextureScaling() { } static std::string TextureTranslateName(const char *value) { - auto ps = GetI18NCategory("TextureShaders"); + auto ts = GetI18NCategory("TextureShaders"); const TextureShaderInfo *info = GetTextureShaderInfo(value); if (info) { - return ps->T(value, info ? info->name.c_str() : value); - } else { - return value; - } -} - -static std::string PostShaderTranslateName(const char *value) { - auto ps = GetI18NCategory("PostShaders"); - const ShaderInfo *info = GetPostShaderInfo(value); - if (info) { - return ps->T(value, info ? info->name.c_str() : value); + return ts->T(value, info ? info->name.c_str() : value); } else { return value; } @@ -192,6 +177,16 @@ bool PathToVisualUsbPath(Path path, std::string &outPath) { return false; } +static std::string PostShaderTranslateName(const char *value) { + auto ps = GetI18NCategory("PostShaders"); + const ShaderInfo *info = GetPostShaderInfo(value); + if (info) { + return ps->T(value, info ? info->name.c_str() : value); + } else { + return value; + } +} + void GameSettingsScreen::CreateViews() { ReloadAllPostShaderInfo(screenManager()->getDrawContext()); ReloadAllThemeInfo(); @@ -267,9 +262,14 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Rendering Mode"))); + Draw::DrawContext *draw = screenManager()->getDrawContext(); + #if !PPSSPP_PLATFORM(UWP) static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" }; PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager())); + if (g_Config.iGPUBackend != (int)GPUBackend::DIRECT3D9 && !draw->GetDeviceCaps().supportsD3D9) { + renderingBackendChoice->HideChoice(1); + } renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend); if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL)) @@ -287,8 +287,6 @@ void GameSettingsScreen::CreateViews() { } #endif - Draw::DrawContext *draw = screenManager()->getDrawContext(); - // Backends that don't allow a device choice will only expose one device. if (draw->GetDeviceList().size() > 1) { std::string *deviceNameSetting = GPUDeviceNameSetting(); @@ -298,33 +296,91 @@ void GameSettingsScreen::CreateViews() { } } - static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering" }; - PopupMultiChoice *renderingModeChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gr->T("Mode"), renderingMode, 0, ARRAY_SIZE(renderingMode), gr->GetName(), screenManager())); - renderingModeChoice->OnChoice.Add([=](EventParams &e) { - switch (g_Config.iRenderingMode) { - case FB_NON_BUFFERED_MODE: - settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games"), e.v); - break; - case FB_BUFFERED_MODE: - break; - } - return UI::EVENT_CONTINUE; + static const char *internalResolutions[] = { "Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" }; + resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager())); + resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange); + resolutionChoice_->SetEnabledFunc([] { + return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; }); - renderingModeChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingMode); - renderingModeChoice->SetDisabledPtr(&g_Config.bSoftwareRendering); - CheckBox *blockTransfer = graphicsSettings->Add(new CheckBox(&g_Config.bBlockTransferGPU, gr->T("Simulate Block Transfer", "Simulate Block Transfer"))); - blockTransfer->OnClick.Add([=](EventParams &e) { - if (!g_Config.bBlockTransferGPU) - settingInfo_->Show(gr->T("BlockTransfer Tip", "Some games require this to be On for correct graphics"), e.v); - return UI::EVENT_CONTINUE; - }); - blockTransfer->SetDisabledPtr(&g_Config.bSoftwareRendering); if (deviceType != DEVICE_TYPE_VR) { CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); softwareGPU->SetEnabled(!PSP_IsInited()); } + if (draw->GetDeviceCaps().multiSampleLevelsMask != 1) { + static const char *msaaModes[] = { "Off", "2x", "4x", "8x", "16x" }; + auto msaaChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iMultiSampleLevel, gr->T("Antialiasing (MSAA)"), msaaModes, 0, ARRAY_SIZE(msaaModes), gr->GetName(), screenManager())); + msaaChoice->OnChoice.Add([&](UI::EventParams &) -> UI::EventReturn { + NativeMessageReceived("gpu_renderResized", ""); + return UI::EVENT_DONE; + }); + msaaChoice->SetDisabledPtr(&g_Config.bSoftwareRendering); + + // Hide unsupported levels. + for (int i = 1; i < 5; i++) { + if ((draw->GetDeviceCaps().multiSampleLevelsMask & (1 << i)) == 0) { + msaaChoice->HideChoice(i); + } + } + } + +#if PPSSPP_PLATFORM(ANDROID) + if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) { + static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" }; + int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2; + if (max_res_temp == 3) + max_res_temp = 4; // At least allow 2x + int max_res = std::min(max_res_temp, (int)ARRAY_SIZE(deviceResolutions)); + UI::PopupMultiChoice *hwscale = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAndroidHwScale, gr->T("Display Resolution (HW scaler)"), deviceResolutions, 0, max_res, gr->GetName(), screenManager())); + hwscale->OnChoice.Handle(this, &GameSettingsScreen::OnHwScaleChange); // To refresh the display mode + } +#endif + + if (deviceType != DEVICE_TYPE_VR) { +#if !defined(MOBILE_DEVICE) + graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); + if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { + CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays")); + fullscreenMulti->SetEnabledFunc([] { + return g_Config.UseFullScreen(); + }); + graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenMultiChange); + } +#endif + +#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) + CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); + vSync->OnClick.Add([=](EventParams &e) { + NativeResized(); + return UI::EVENT_CONTINUE; + }); +#endif + +#if PPSSPP_PLATFORM(ANDROID) + // Hide insets option if no insets, or OS too old. + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28 && + (System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f || + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) { + graphicsSettings->Add(new CheckBox(&g_Config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering"))); + } + + // Hide Immersive Mode on pre-kitkat Android + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) { + // Let's reuse the Fullscreen translation string from desktop. + graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange); + } +#endif + // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. + displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display Layout && Effects"))); + displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new DisplayLayoutScreen(gamePath_)); + return UI::EVENT_DONE; + }); + } + graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager())); @@ -348,123 +404,55 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetFormat("%i%%"); } - graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); + graphicsSettings->Add(new ItemHeader(gr->T("Speed Hacks", "Speed Hacks (can cause rendering errors!)"))); - std::set alreadyAddedShader; - for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { - // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread - shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; - postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); - postProcChoice_->OnClick.Add([=](EventParams &e) { - auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i); - procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); - if (e.v) - procScreen->SetPopupOrigin(e.v); - screenManager()->push(procScreen); - return UI::EVENT_DONE; - }); - postProcChoice_->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - }); - - // No need for settings on the last one. - if (i == g_Config.vPostShaderNames.size()) - continue; - - auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); - for (auto shaderInfo : shaderChain) { - // Disable duplicated shader slider - bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); - alreadyAddedShader.insert(shaderInfo->section); - for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { - auto &setting = shaderInfo->settings[i]; - if (!setting.name.empty()) { - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; - if (duplicated) { - auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); - PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); - settingValue->SetEnabled(false); - } else { - PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); - settingValue->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - }); - } - } - } + CheckBox *skipBufferEffects = graphicsSettings->Add(new CheckBox(&g_Config.bSkipBufferEffects, gr->T("Skip Buffer Effects"))); + skipBufferEffects->OnClick.Add([=](EventParams &e) { + if (g_Config.bSkipBufferEffects) { + settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games"), e.v); + g_Config.bAutoFrameSkip = false; } - } - - if (deviceType != DEVICE_TYPE_VR) { - graphicsSettings->Add(new ItemHeader(gr->T("Screen layout"))); -#if !defined(MOBILE_DEVICE) - graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); - if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { - CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays")); - fullscreenMulti->SetEnabledFunc([] { - return g_Config.UseFullScreen(); - }); - graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenMultiChange); - } -#endif - // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. - displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); - displayEditor_->OnClick.Handle(this, &GameSettingsScreen::OnDisplayLayoutEditor); - -#if PPSSPP_PLATFORM(ANDROID) - // Hide insets option if no insets, or OS too old. - if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28 && - (System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f || - System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f || - System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f || - System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) { - graphicsSettings->Add(new CheckBox(&g_Config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering"))); - } - - // Hide Immersive Mode on pre-kitkat Android - if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) { - // Let's reuse the Fullscreen translation string from desktop. - graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange); - } -#endif - } - - graphicsSettings->Add(new ItemHeader(gr->T("Performance"))); - static const char *internalResolutions[] = { "Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" }; - resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager())); - resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange); - resolutionChoice_->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + NativeMessageReceived("gpu_renderResized", ""); + return UI::EVENT_DONE; }); + skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); -#if PPSSPP_PLATFORM(ANDROID) - if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) { - static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" }; - int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2; - if (max_res_temp == 3) - max_res_temp = 4; // At least allow 2x - int max_res = std::min(max_res_temp, (int)ARRAY_SIZE(deviceResolutions)); - UI::PopupMultiChoice *hwscale = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAndroidHwScale, gr->T("Display Resolution (HW scaler)"), deviceResolutions, 0, max_res, gr->GetName(), screenManager())); - hwscale->OnChoice.Handle(this, &GameSettingsScreen::OnHwScaleChange); // To refresh the display mode - } -#endif + CheckBox *skipGPUReadbacks = graphicsSettings->Add(new CheckBox(&g_Config.bSkipGPUReadbacks, gr->T("Skip GPU Readbacks"))); + skipGPUReadbacks->SetDisabledPtr(&g_Config.bSoftwareRendering); -#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) - CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); - vSync->OnClick.Add([=](EventParams &e) { - NativeResized(); + CheckBox *vtxCache = graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gr->T("Vertex Cache"))); + vtxCache->OnClick.Add([=](EventParams &e) { + settingInfo_->Show(gr->T("VertexCache Tip", "Faster, but may cause temporary flicker"), e.v); return UI::EVENT_CONTINUE; }); -#endif + vtxCache->SetEnabledFunc([] { + return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform && g_Config.iGPUBackend != (int)GPUBackend::OPENGL; + }); + CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)"))); + texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering); + texBackoff->OnClick.Add([=](EventParams& e) { + settingInfo_->Show(gr->T("Lazy texture caching Tip", "Faster, but can cause text problems in a few games"), e.v); + return UI::EVENT_CONTINUE; + }); + + static const char *quality[] = { "Low", "Medium", "High" }; + PopupMultiChoice *beziersChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iSplineBezierQuality, gr->T("LowCurves", "Spline/Bezier curves quality"), quality, 0, ARRAY_SIZE(quality), gr->GetName(), screenManager())); + beziersChoice->OnChoice.Add([=](EventParams &e) { + if (g_Config.iSplineBezierQuality != 0) { + settingInfo_->Show(gr->T("LowCurves Tip", "Only used by some games, controls smoothness of curves"), e.v); + } + return UI::EVENT_CONTINUE; + }); + + graphicsSettings->Add(new ItemHeader(gr->T("Performance"))); CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); frameDuplication->OnClick.Add([=](EventParams &e) { settingInfo_->Show(gr->T("RenderDuplicateFrames Tip", "Can make framerate smoother in games that run at lower framerates"), e.v); return UI::EVENT_CONTINUE; }); frameDuplication->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && g_Config.iFrameSkip == 0; + return !g_Config.bSkipBufferEffects && g_Config.iFrameSkip == 0; }); if (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::OPENGL) { @@ -494,45 +482,6 @@ void GameSettingsScreen::CreateViews() { }); swSkin->SetDisabledPtr(&g_Config.bSoftwareRendering); - CheckBox *vtxCache = graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gr->T("Vertex Cache"))); - vtxCache->OnClick.Add([=](EventParams &e) { - settingInfo_->Show(gr->T("VertexCache Tip", "Faster, but may cause temporary flicker"), e.v); - return UI::EVENT_CONTINUE; - }); - vtxCache->SetEnabledFunc([] { - return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform && g_Config.iGPUBackend != (int)GPUBackend::OPENGL; - }); - - CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)"))); - texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering); - texBackoff->OnClick.Add([=](EventParams& e) { - settingInfo_->Show(gr->T("Lazy texture caching Tip", "Faster, but can cause text problems in a few games"), e.v); - return UI::EVENT_CONTINUE; - }); - - CheckBox *texSecondary_ = graphicsSettings->Add(new CheckBox(&g_Config.bTextureSecondaryCache, gr->T("Retain changed textures", "Retain changed textures (speedup, mem hog)"))); - texSecondary_->OnClick.Add([=](EventParams &e) { - settingInfo_->Show(gr->T("RetainChangedTextures Tip", "Makes many games slower, but some games a lot faster"), e.v); - return UI::EVENT_CONTINUE; - }); - texSecondary_->SetDisabledPtr(&g_Config.bSoftwareRendering); - - // Seems solid, so we hide the setting. - /*CheckBox *vtxJit = graphicsSettings->Add(new CheckBox(&g_Config.bVertexDecoderJit, gr->T("Vertex Decoder JIT"))); - - if (PSP_IsInited()) { - vtxJit->SetEnabled(false); - }*/ - - static const char *quality[] = { "Low", "Medium", "High" }; - PopupMultiChoice *beziersChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iSplineBezierQuality, gr->T("LowCurves", "Spline/Bezier curves quality"), quality, 0, ARRAY_SIZE(quality), gr->GetName(), screenManager())); - beziersChoice->OnChoice.Add([=](EventParams &e) { - if (g_Config.iSplineBezierQuality != 0) { - settingInfo_->Show(gr->T("LowCurves Tip", "Only used by some games, controls smoothness of curves"), e.v); - } - return UI::EVENT_CONTINUE; - }); - CheckBox *tessellationHW = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTessellation, gr->T("Hardware Tessellation"))); tessellationHW->OnClick.Add([=](EventParams &e) { settingInfo_->Show(gr->T("HardwareTessellation Tip", "Uses hardware to make curves"), e.v); @@ -598,9 +547,6 @@ void GameSettingsScreen::CreateViews() { static const char *texFilters[] = { "Auto", "Nearest", "Linear", "Auto Max Quality"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexFiltering, gr->T("Texture Filter"), texFilters, 1, ARRAY_SIZE(texFilters), gr->GetName(), screenManager())); - static const char *bufFilters[] = { "Linear", "Nearest", }; - graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); - #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) bool showCardboardSettings = deviceType != DEVICE_TYPE_VR; #else @@ -638,13 +584,6 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new PopupMultiChoice(&g_Config.iShowFPSCounter, gr->T("Show FPS Counter"), fpsChoices, 0, ARRAY_SIZE(fpsChoices), gr->GetName(), screenManager())); graphicsSettings->Add(new CheckBox(&g_Config.bShowDebugStats, gr->T("Show Debug Statistics")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting); - // Developer tools are not accessible ingame, so it goes here. - graphicsSettings->Add(new ItemHeader(gr->T("Debugging"))); - Choice *dump = graphicsSettings->Add(new Choice(gr->T("Dump next frame to log"))); - dump->OnClick.Handle(this, &GameSettingsScreen::OnDumpNextFrameToLog); - if (!PSP_IsInited()) - dump->SetEnabled(false); - // Audio LinearLayout *audioSettings = AddTab("GameSettingsAudio", ms->T("Audio")); @@ -775,7 +714,7 @@ void GameSettingsScreen::CreateViews() { style->SetEnabledPtr(&g_Config.bShowTouchControls); Choice *gesture = controlsSettings->Add(new Choice(co->T("Gesture mapping"))); gesture->OnClick.Add([=](EventParams &e) { - screenManager()->push(new GestureMappingScreen()); + screenManager()->push(new GestureMappingScreen(gamePath_)); return UI::EVENT_DONE; }); gesture->SetEnabledPtr(&g_Config.bShowTouchControls); @@ -905,7 +844,30 @@ void GameSettingsScreen::CreateViews() { LinearLayout *systemSettings = AddTab("GameSettingsSystem", ms->T("System")); systemSettings->Add(new ItemHeader(sy->T("UI"))); - systemSettings->Add(new Choice(dev->T("Language", "Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage); + + auto langCodeToName = [](const char *value) -> std::string { + auto &mapping = g_Config.GetLangValuesMapping(); + auto iter = mapping.find(value); + if (iter != mapping.end()) { + return iter->second.first; + } + return value; + }; + + systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.sLanguageIni, sy->T("Language"), langCodeToName))->OnClick.Add([&](UI::EventParams &e) { + auto sy = GetI18NCategory("System"); + auto langScreen = new NewLanguageScreen(sy->T("Language")); + langScreen->OnChoice.Add([&](UI::EventParams &e) { + screenManager()->RecreateAllViews(); + if (host) + host->UpdateUI(); + return UI::EVENT_DONE; + }); + if (e.v) + langScreen->SetPopupOrigin(e.v); + screenManager()->push(langScreen); + return UI::EVENT_DONE; + }); systemSettings->Add(new CheckBox(&g_Config.bUISound, sy->T("UI Sound"))); const Path bgPng = GetSysDirectory(DIRECTORY_SYSTEM) / "background.png"; const Path bgJpg = GetSysDirectory(DIRECTORY_SYSTEM) / "background.jpg"; @@ -1123,14 +1085,21 @@ void GameSettingsScreen::CreateViews() { if (deviceType == DEVICE_TYPE_VR) { LinearLayout *vrSettings = AddTab("GameSettingsVR", ms->T("VR")); vrSettings->Add(new ItemHeader(vr->T("Virtual reality"))); - vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Enable virtual reality"))); - vrSettings->Add(new PopupSliderChoice(&g_Config.iCanvasDistance, 1, 10, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1, screenManager(), "")); - CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("Enable 6 degrees of freedom movement"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Virtual reality"))); + CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("6DoF movement"))); vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); - PopupSliderChoice *vrFieldOfView = vrSettings->Add(new PopupSliderChoice(&g_Config.iFieldOfViewPercentage, 100, 200, vr->T("Field of view scale", "Headset's field of view scale"), 10, screenManager(), vr->T("% of native FoV"))); - vrFieldOfView->SetEnabledPtr(&g_Config.bEnableVR); - CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Enable stereoscopic vision (Experimental)"))); - vrStereo->SetEnabledPtr(&g_Config.bEnableVR); + vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); + vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); + + vrSettings->Add(new ItemHeader(vr->T("VR camera"))); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDisplayScale, 0.2f, 1.5f, vr->T("Heads-up display scale"), 0.1f, screenManager(), "")); + + vrSettings->Add(new ItemHeader(vr->T("VR controllers"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); + PopupSliderChoiceFloat *vrMotions = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMotionLength, 0.3f, 1.0f, vr->T("Motion needed to generate action"), 0.1f, screenManager(), vr->T("m"))); + vrMotions->SetEnabledPtr(&g_Config.bEnableMotions); } } @@ -1161,8 +1130,8 @@ UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) { if (g_Config.bAutoFrameSkip && g_Config.iFrameSkip == 0) { g_Config.iFrameSkip = 1; } - if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; + if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; } return UI::EVENT_DONE; } @@ -1206,20 +1175,6 @@ UI::EventReturn GameSettingsScreen::OnSustainedPerformanceModeChange(UI::EventPa return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnRenderingMode(UI::EventParams &e) { - // We do not want to report when rendering mode is Framebuffer to memory - so many issues - // are caused by that (framebuffer copies overwriting display lists, etc). - Reporting::UpdateConfig(); - enableReportsCheckbox_->SetEnabled(Reporting::IsSupported()); - if (!Reporting::IsSupported()) - enableReports_ = Reporting::IsEnabled(); - - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.bAutoFrameSkip = false; - } - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) { NativeMessageReceived("clear jit", ""); return UI::EVENT_DONE; @@ -1326,16 +1281,12 @@ UI::EventReturn GameSettingsScreen::OnFullscreenMultiChange(UI::EventParams &e) return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnDisplayLayoutEditor(UI::EventParams &e) { - screenManager()->push(new DisplayLayoutScreen()); - return UI::EVENT_DONE; -}; - UI::EventReturn GameSettingsScreen::OnResolutionChange(UI::EventParams &e) { if (g_Config.iAndroidHwScale == 1) { RecreateActivity(); } Reporting::UpdateConfig(); + NativeMessageReceived("gpu_renderResized", ""); return UI::EVENT_DONE; } @@ -1344,23 +1295,6 @@ UI::EventReturn GameSettingsScreen::OnHwScaleChange(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnDumpNextFrameToLog(UI::EventParams &e) { - if (gpu) { - gpu->DumpNextFrame(); - } - return UI::EVENT_DONE; -} - -void GameSettingsScreen::update() { - UIScreen::update(); - - bool vertical = UseVerticalLayout(); - if (vertical != lastVertical_) { - RecreateViews(); - lastVertical_ = vertical; - } -} - void GameSettingsScreen::onFinish(DialogResult result) { if (g_Config.bEnableSound) { if (PSP_IsInited() && !IsAudioInitialised()) @@ -1385,16 +1319,12 @@ void GameSettingsScreen::onFinish(DialogResult result) { KeyMap::UpdateNativeMenuKeys(); // Wipe some caches after potentially changing settings. - NativeMessageReceived("gpu_resized", ""); - NativeMessageReceived("gpu_clearCache", ""); + // Let's not send resize messages here, handled elsewhere. + NativeMessageReceived("gpu_configChanged", ""); } void GameSettingsScreen::sendMessage(const char *message, const char *value) { UIDialogScreenWithGameBackground::sendMessage(message, value); - if (!strcmp(message, "postshader_updated")) { - g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); - RecreateViews(); - } if (!strcmp(message, "gameSettings_search")) { std::string filter = value ? value : ""; searchFilter_.resize(filter.size()); @@ -1543,7 +1473,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingBackend(UI::EventParams &e) { // It only makes sense to show the restart prompt if the backend was actually changed. if (g_Config.iGPUBackend != (int)GetGPUBackend()) { - screenManager()->push(new PromptScreen(di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), + screenManager()->push(new PromptScreen(gamePath_, di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackRenderingBackend, this, std::placeholders::_1))); } return UI::EVENT_DONE; @@ -1555,7 +1485,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) { // It only makes sense to show the restart prompt if the device was actually changed. std::string *deviceNameSetting = GPUDeviceNameSetting(); if (deviceNameSetting && *deviceNameSetting != GetGPUBackendDevice()) { - screenManager()->push(new PromptScreen(di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), + screenManager()->push(new PromptScreen(gamePath_, di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackRenderingDevice, this, std::placeholders::_1))); } return UI::EVENT_DONE; @@ -1564,7 +1494,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnInflightFramesChoice(UI::EventParams &e) { auto di = GetI18NCategory("Dialog"); if (g_Config.iInflightFrames != prevInflightFrames_) { - screenManager()->push(new PromptScreen(di->T("ChangingInflightFrames", "Changing graphics command buffering requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), + screenManager()->push(new PromptScreen(gamePath_, di->T("ChangingInflightFrames", "Changing graphics command buffering requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackInflightFrames, this, std::placeholders::_1))); } return UI::EVENT_DONE; @@ -1678,6 +1608,7 @@ UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) { std::string combined = std::string(confirmMessage) + "\n\n" + warningMessage; auto confirmScreen = new PromptScreen( + gamePath_, combined, di->T("Yes"), di->T("No"), [&](bool success) { if (success) { @@ -1689,33 +1620,6 @@ UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) { - auto dev = GetI18NCategory("Developer"); - auto langScreen = new NewLanguageScreen(dev->T("Language")); - langScreen->OnChoice.Handle(this, &GameSettingsScreen::OnLanguageChange); - if (e.v) - langScreen->SetPopupOrigin(e.v); - screenManager()->push(langScreen); - return UI::EVENT_DONE; -} - -UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { - screenManager()->RecreateAllViews(); - - if (host) { - host->UpdateUI(); - } - return UI::EVENT_DONE; -} - -UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { - g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); - - NativeMessageReceived("gpu_resized", ""); - NativeMessageReceived("postshader_updated", ""); - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnTextureShader(UI::EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto shaderScreen = new TextureShaderScreen(gr->T("Texture Shader")); @@ -1727,14 +1631,14 @@ UI::EventReturn GameSettingsScreen::OnTextureShader(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnTextureShaderChange(UI::EventParams &e) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); RecreateViews(); // Update setting name g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off"; return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) { - screenManager()->push(new DeveloperToolsScreen()); + screenManager()->push(new DeveloperToolsScreen(gamePath_)); return UI::EVENT_DONE; } @@ -1744,17 +1648,17 @@ UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnControlMapping(UI::EventParams &e) { - screenManager()->push(new ControlMappingScreen()); + screenManager()->push(new ControlMappingScreen(gamePath_)); return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnCalibrateAnalogs(UI::EventParams &e) { - screenManager()->push(new AnalogSetupScreen()); + screenManager()->push(new AnalogSetupScreen(gamePath_)); return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) { - screenManager()->push(new TouchControlLayoutScreen()); + screenManager()->push(new TouchControlLayoutScreen(gamePath_)); return UI::EVENT_DONE; } @@ -1813,6 +1717,7 @@ void DeveloperToolsScreen::CreateViews() { auto gr = GetI18NCategory("Graphics"); auto a = GetI18NCategory("Audio"); auto sy = GetI18NCategory("System"); + auto ps = GetI18NCategory("PostShaders"); AddStandardBack(root_); @@ -1858,27 +1763,15 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bShowOnScreenMessages, dev->T("Show on-screen messages"))); list->Add(new CheckBox(&g_Config.bEnableLogging, dev->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged); - if (GetGPUBackend() == GPUBackend::VULKAN) { - list->Add(new CheckBox(&g_Config.bGpuLogProfiler, gr->T("GPU log profiler"))); - } - list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics"))); list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig); - list->Add(new ItemHeader(dev->T("Language"))); - list->Add(new Choice(dev->T("Load language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoadLanguageIni); - list->Add(new Choice(dev->T("Save language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSaveLanguageIni); + list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics"))); + if (GetGPUBackend() == GPUBackend::VULKAN) { + list->Add(new CheckBox(&g_Config.bGpuLogProfiler, dev->T("GPU log profiler"))); + } list->Add(new ItemHeader(dev->T("Texture Replacement"))); list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures"))); list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures"))); - // Makes it easy to get savestates out of an iOS device. The file listing shown in MacOS doesn't allow - // you to descend into directories. -#if PPSSPP_PLATFORM(IOS) - list->Add(new Choice(dev->T("Copy savestates to memstick root")))->OnClick.Handle(this, &DeveloperToolsScreen::OnCopyStatesToRoot); -#endif - - // Reconsider whenever recreating views. - hasTexturesIni_ = HasIni::MAYBE; - Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game"))); createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile); createTextureIni->SetEnabledFunc([&] { @@ -1893,11 +1786,65 @@ void DeveloperToolsScreen::CreateViews() { } return true; }); + + Draw::DrawContext *draw = screenManager()->getDrawContext(); + + // Experimental, will move to main graphics settings later. + list->Add(new ItemHeader(gr->T("Stereo rendering"))); + + bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; + + auto enableStereo = [=]() -> bool { + return g_Config.bStereoRendering && multiViewSupported; + }; + + if (draw->GetDeviceCaps().multiViewSupported) { + list->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering"))); + std::vector stereoShaderNames; + + ChoiceWithValueDisplay *stereoShaderChoice = list->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, gr->T("Stereo display shader"), &PostShaderTranslateName)); + stereoShaderChoice->SetEnabledFunc(enableStereo); + stereoShaderChoice->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Stereo display shader"), 0, true); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + const ShaderInfo *shaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); + if (shaderInfo) { + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + std::string key = StringFromFormat("%sSettingCurrentValue%d", shaderInfo->section.c_str(), i + 1); + bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end(); + auto &value = g_Config.mPostShaderSetting[key]; + if (!keyExisted) + value = setting.value; + + PopupSliderChoiceFloat *settingValue = list->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetEnabledFunc([=] { + return !g_Config.bSkipBufferEffects && enableStereo(); + }); + } + } + } + } + + // Makes it easy to get savestates out of an iOS device. The file listing shown in MacOS doesn't allow + // you to descend into directories. +#if PPSSPP_PLATFORM(IOS) + list->Add(new Choice(dev->T("Copy savestates to memstick root")))->OnClick.Handle(this, &DeveloperToolsScreen::OnCopyStatesToRoot); +#endif + + // Reconsider whenever recreating views. + hasTexturesIni_ = HasIni::MAYBE; } void DeveloperToolsScreen::onFinish(DialogResult result) { g_Config.Save("DeveloperToolsScreen::onFinish"); - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); } void GameSettingsScreen::CallbackRestoreDefaults(bool yes) { @@ -1912,13 +1859,13 @@ UI::EventReturn GameSettingsScreen::OnRestoreDefaultSettings(UI::EventParams &e) if (g_Config.bGameSpecific) { screenManager()->push( - new PromptScreen(dev->T("RestoreGameDefaultSettings", "Are you sure you want to restore the game-specific settings back to the ppsspp defaults?\n"), di->T("OK"), di->T("Cancel"), + new PromptScreen(gamePath_, dev->T("RestoreGameDefaultSettings", "Are you sure you want to restore the game-specific settings back to the ppsspp defaults?\n"), di->T("OK"), di->T("Cancel"), std::bind(&GameSettingsScreen::CallbackRestoreDefaults, this, std::placeholders::_1))); } else { screenManager()->push( - new PromptScreen(dev->T("RestoreDefaultSettings", "Are you sure you want to restore all settings(except control mapping)\nback to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings."), di->T("OK"), di->T("Cancel"), + new PromptScreen(gamePath_, dev->T("RestoreDefaultSettings", "Are you sure you want to restore all settings(except control mapping)\nback to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings."), di->T("OK"), di->T("Cancel"), std::bind(&GameSettingsScreen::CallbackRestoreDefaults, this, std::placeholders::_1))); } @@ -1937,16 +1884,6 @@ UI::EventReturn DeveloperToolsScreen::OnRunCPUTests(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn DeveloperToolsScreen::OnSaveLanguageIni(UI::EventParams &e) { - i18nrepo.SaveIni(g_Config.sLanguageIni); - return UI::EVENT_DONE; -} - -UI::EventReturn DeveloperToolsScreen::OnLoadLanguageIni(UI::EventParams &e) { - i18nrepo.LoadIni(g_Config.sLanguageIni); - return UI::EVENT_DONE; -} - UI::EventReturn DeveloperToolsScreen::OnOpenTexturesIniFile(UI::EventParams &e) { std::string gameID = g_paramSFO.GetDiscID(); Path generatedFilename; @@ -1986,7 +1923,7 @@ UI::EventReturn DeveloperToolsScreen::OnFramedumpTest(UI::EventParams &e) { } UI::EventReturn DeveloperToolsScreen::OnTouchscreenTest(UI::EventParams &e) { - screenManager()->push(new TouchTestScreen()); + screenManager()->push(new TouchTestScreen(gamePath_)); return UI::EVENT_DONE; } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 82b4cd859e..86d5881f56 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -30,7 +30,6 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { public: GameSettingsScreen(const Path &gamePath, std::string gameID = "", bool editThenRestore = false); - void update() override; void onFinish(DialogResult result) override; const char *tag() const override { return "GameSettings"; } @@ -42,7 +41,6 @@ protected: void CallbackRenderingDevice(bool yes); void CallbackInflightFrames(bool yes); void CallbackMemstickFolder(bool yes); - bool UseVerticalLayout() const; void dialogFinished(const Screen *dialog, DialogResult result) override; void RecreateViews() override; @@ -52,10 +50,8 @@ private: void TriggerRestart(const char *why); std::string gameID_; - bool lastVertical_; UI::CheckBox *enableReportsCheckbox_; UI::Choice *layoutEditorChoice_; - UI::Choice *postProcChoice_; UI::Choice *displayEditor_; UI::Choice *backgroundChoice_ = nullptr; UI::PopupMultiChoice *resolutionChoice_; @@ -81,15 +77,11 @@ private: UI::EventReturn OnControlMapping(UI::EventParams &e); UI::EventReturn OnCalibrateAnalogs(UI::EventParams &e); UI::EventReturn OnTouchControlLayout(UI::EventParams &e); - UI::EventReturn OnDumpNextFrameToLog(UI::EventParams &e); UI::EventReturn OnTiltTypeChange(UI::EventParams &e); UI::EventReturn OnTiltCustomize(UI::EventParams &e); // Global settings handlers - UI::EventReturn OnLanguage(UI::EventParams &e); - UI::EventReturn OnLanguageChange(UI::EventParams &e); UI::EventReturn OnAutoFrameskip(UI::EventParams &e); - UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); UI::EventReturn OnTextureShader(UI::EventParams &e); UI::EventReturn OnTextureShaderChange(UI::EventParams &e); UI::EventReturn OnDeveloperTools(UI::EventParams &e); @@ -105,7 +97,6 @@ private: UI::EventReturn OnChangeBackground(UI::EventParams &e); UI::EventReturn OnFullscreenChange(UI::EventParams &e); UI::EventReturn OnFullscreenMultiChange(UI::EventParams &e); - UI::EventReturn OnDisplayLayoutEditor(UI::EventParams &e); UI::EventReturn OnResolutionChange(UI::EventParams &e); UI::EventReturn OnHwScaleChange(UI::EventParams &e); UI::EventReturn OnRestoreDefaultSettings(UI::EventParams &e); @@ -142,7 +133,7 @@ private: bool enableReports_ = false; bool enableReportsSet_ = false; bool analogSpeedMapped_ = false; - std::string shaderNames_[256]; + std::string searchFilter_; //edit the game-specific settings and restore the global settings after exiting @@ -155,8 +146,10 @@ private: std::string oldSettingInfo_; }; -class DeveloperToolsScreen : public UIDialogScreenWithBackground { +class DeveloperToolsScreen : public UIDialogScreenWithGameBackground { public: + DeveloperToolsScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} + void update() override; void onFinish(DialogResult result) override; @@ -168,8 +161,6 @@ protected: private: UI::EventReturn OnRunCPUTests(UI::EventParams &e); UI::EventReturn OnLoggingChanged(UI::EventParams &e); - UI::EventReturn OnLoadLanguageIni(UI::EventParams &e); - UI::EventReturn OnSaveLanguageIni(UI::EventParams &e); UI::EventReturn OnOpenTexturesIniFile(UI::EventParams &e); UI::EventReturn OnLogConfig(UI::EventParams &e); UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); @@ -247,8 +238,9 @@ private: }; -class GestureMappingScreen : public UIDialogScreenWithBackground { +class GestureMappingScreen : public UIDialogScreenWithGameBackground { public: + GestureMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} void CreateViews() override; const char *tag() const override { return "GestureMapping"; } diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index 809f2cf31f..a288be6fe1 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -45,8 +45,9 @@ GamepadView::GamepadView(const char *key, UI::LayoutParams *layoutParams) : UI:: lastFrameTime_ = time_now_d(); } -void GamepadView::Touch(const TouchInput &input) { +bool GamepadView::Touch(const TouchInput &input) { secondsWithoutTouch_ = 0.0f; + return true; } void GamepadView::Update() { @@ -96,8 +97,8 @@ void MultiTouchButton::GetContentDimensions(const UIContext &dc, float &w, float } } -void MultiTouchButton::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool MultiTouchButton::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if ((input.flags & TOUCH_DOWN) && bounds_.Contains(input.x, input.y)) { pointerDownMask_ |= 1 << input.id; usedPointerMask |= 1 << input.id; @@ -116,6 +117,7 @@ void MultiTouchButton::Touch(const TouchInput &input) { pointerDownMask_ = 0; usedPointerMask = 0; } + return retval; } void MultiTouchButton::Draw(UIContext &dc) { @@ -152,9 +154,9 @@ void MultiTouchButton::Draw(UIContext &dc) { dc.Draw()->DrawImageRotated(img_, bounds_.centerX(), y, scale, angle_ * (M_PI * 2 / 360.0f), color); } -void BoolButton::Touch(const TouchInput &input) { +bool BoolButton::Touch(const TouchInput &input) { bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); + bool retval = MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; if (down != lastDown) { @@ -163,11 +165,12 @@ void BoolButton::Touch(const TouchInput &input) { params.a = down; OnChange.Trigger(params); } + return retval; } -void PSPButton::Touch(const TouchInput &input) { +bool PSPButton::Touch(const TouchInput &input) { bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); + bool retval = MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; if (down && !lastDown) { if (g_Config.bHapticFeedback) { @@ -177,6 +180,7 @@ void PSPButton::Touch(const TouchInput &input) { } else if (lastDown && !down) { __CtrlButtonUp(pspButtonBit_); } + return retval; } bool ComboKey::IsDown() { @@ -192,10 +196,10 @@ void ComboKey::GetContentDimensions(const UIContext &dc, float &w, float &h) con } } -void ComboKey::Touch(const TouchInput &input) { +bool ComboKey::Touch(const TouchInput &input) { using namespace CustomKey; bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); + bool retval = MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; if (down && !lastDown) { @@ -205,7 +209,7 @@ void ComboKey::Touch(const TouchInput &input) { if (!repeat_) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, (on_ && toggle_) ? KEY_UP : KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, (on_ && toggle_) ? KEY_UP : KEY_DOWN); } } } @@ -214,12 +218,13 @@ void ComboKey::Touch(const TouchInput &input) { if (!repeat_) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, KEY_UP); } } } on_ = false; } + return retval; } void ComboKey::Update() { @@ -235,13 +240,13 @@ void ComboKey::Update() { } else if (pressedFrames_ == DOWN_FRAME) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, KEY_UP); } } } else if (on_ && pressedFrames_ == 0) { for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { if (pspButtonBit_ & (1ULL << i)) { - controllMapper_->pspKey(comboKeyList[i].c, KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, comboKeyList[i].c, KEY_DOWN); } } pressedFrames_ = 1; @@ -272,8 +277,8 @@ void PSPDpad::GetContentDimensions(const UIContext &dc, float &w, float &h) cons } } -void PSPDpad::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool PSPDpad::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if (input.flags & TOUCH_DOWN) { if (dragPointerId_ == -1 && bounds_.Contains(input.x, input.y)) { @@ -297,6 +302,7 @@ void PSPDpad::Touch(const TouchInput &input) { ProcessTouch(input.x, input.y, false); } } + return retval; } void PSPDpad::ProcessTouch(float x, float y, bool down) { @@ -438,8 +444,8 @@ void PSPStick::Draw(UIContext &dc) { dc.Draw()->DrawImage(stickImageIndex_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f * scale_ * headScale, colorBg, ALIGN_CENTER); } -void PSPStick::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool PSPStick::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if (input.flags & TOUCH_RELEASE_ALL) { dragPointerId_ = -1; centerX_ = bounds_.centerX(); @@ -447,7 +453,7 @@ void PSPStick::Touch(const TouchInput &input) { __CtrlSetAnalogXY(stick_, 0.0f, 0.0f); usedPointerMask = 0; analogPointerMask = 0; - return; + return retval; } if (input.flags & TOUCH_DOWN) { float fac = 0.5f*(stick_ ? g_Config.fRightStickHeadScale : g_Config.fLeftStickHeadScale)-0.5f; @@ -463,11 +469,13 @@ void PSPStick::Touch(const TouchInput &input) { usedPointerMask |= 1 << input.id; analogPointerMask |= 1 << input.id; ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_MOVE) { if (input.id == dragPointerId_) { ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_UP) { @@ -478,8 +486,10 @@ void PSPStick::Touch(const TouchInput &input) { usedPointerMask &= ~(1 << input.id); analogPointerMask &= ~(1 << input.id); ProcessTouch(input.x, input.y, false); + retval = true; } } + return retval; } void PSPStick::ProcessTouch(float x, float y, bool down) { @@ -542,8 +552,8 @@ void PSPCustomStick::Draw(UIContext &dc) { dc.Draw()->DrawImage(stickImageIndex_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f*scale_*g_Config.fRightStickHeadScale, colorBg, ALIGN_CENTER); } -void PSPCustomStick::Touch(const TouchInput &input) { - GamepadView::Touch(input); +bool PSPCustomStick::Touch(const TouchInput &input) { + bool retval = GamepadView::Touch(input); if (input.flags & TOUCH_RELEASE_ALL) { dragPointerId_ = -1; centerX_ = bounds_.centerX(); @@ -552,7 +562,7 @@ void PSPCustomStick::Touch(const TouchInput &input) { posY_ = 0.0f; usedPointerMask = 0; analogPointerMask = 0; - return; + return false; } if (input.flags & TOUCH_DOWN) { float fac = 0.5f*g_Config.fRightStickHeadScale-0.5f; @@ -568,11 +578,13 @@ void PSPCustomStick::Touch(const TouchInput &input) { usedPointerMask |= 1 << input.id; analogPointerMask |= 1 << input.id; ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_MOVE) { if (input.id == dragPointerId_) { ProcessTouch(input.x, input.y, true); + retval = true; } } if (input.flags & TOUCH_UP) { @@ -583,12 +595,27 @@ void PSPCustomStick::Touch(const TouchInput &input) { usedPointerMask &= ~(1 << input.id); analogPointerMask &= ~(1 << input.id); ProcessTouch(input.x, input.y, false); + retval = true; } } + return retval; } void PSPCustomStick::ProcessTouch(float x, float y, bool down) { - static const int button[16] = {CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; + static const int buttons[] = {0, CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; + + u32 press = 0; + u32 release = 0; + + auto toggle = [&](int config, bool simpleCheck, bool diagCheck = true) { + if (config <= 0 || (size_t)config >= ARRAY_SIZE(buttons)) + return; + + if (simpleCheck && (!g_Config.bRightAnalogDisableDiagonal || diagCheck)) + press |= buttons[config]; + else + release |= buttons[config]; + }; if (down && centerX_ >= 0.0f) { float inv_stick_size = 1.0f / (stick_size_ * scale_); @@ -599,51 +626,30 @@ void PSPCustomStick::ProcessTouch(float x, float y, bool down) { dx = std::min(1.0f, std::max(-1.0f, dx)); dy = std::min(1.0f, std::max(-1.0f, dy)); - if (g_Config.iRightAnalogRight != 0) { - if (dx > 0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) > fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogRight-1]); - else - __CtrlButtonUp(button[g_Config.iRightAnalogRight-1]); - } - if (g_Config.iRightAnalogLeft != 0) { - if (dx < -0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) > fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogLeft-1]); - else - __CtrlButtonUp(button[g_Config.iRightAnalogLeft-1]); - } - if (g_Config.iRightAnalogUp != 0) { - if (dy < -0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) <= fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogUp-1]); - else - __CtrlButtonUp(button[g_Config.iRightAnalogUp-1]); - } - if (g_Config.iRightAnalogDown != 0) { - if (dy > 0.5f && (!g_Config.bRightAnalogDisableDiagonal || fabs(dx) <= fabs(dy))) - __CtrlButtonDown(button[g_Config.iRightAnalogDown-1]); - else - __CtrlButtonUp(button[g_Config.iRightAnalogDown-1]); - } - if (g_Config.iRightAnalogPress != 0) - __CtrlButtonDown(button[g_Config.iRightAnalogPress-1]); + toggle(g_Config.iRightAnalogRight, dx > 0.5f, fabs(dx) > fabs(dy)); + toggle(g_Config.iRightAnalogLeft, dx < -0.5f, fabs(dx) > fabs(dy)); + toggle(g_Config.iRightAnalogUp, dy < -0.5f, fabs(dx) <= fabs(dy)); + toggle(g_Config.iRightAnalogDown, dy > 0.5f, fabs(dx) <= fabs(dy)); + toggle(g_Config.iRightAnalogPress, true); posX_ = dx; posY_ = dy; } else { - if (g_Config.iRightAnalogUp != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogUp-1]); - if (g_Config.iRightAnalogDown != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogDown-1]); - if (g_Config.iRightAnalogLeft != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogLeft-1]); - if (g_Config.iRightAnalogRight != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogRight-1]); - if (g_Config.iRightAnalogPress != 0) - __CtrlButtonUp(button[g_Config.iRightAnalogPress-1]); + toggle(g_Config.iRightAnalogRight, false); + toggle(g_Config.iRightAnalogLeft, false); + toggle(g_Config.iRightAnalogUp, false); + toggle(g_Config.iRightAnalogDown, false); + toggle(g_Config.iRightAnalogPress, false); posX_ = 0.0f; posY_ = 0.0f; } + + if (release != 0) + __CtrlButtonUp(release); + if (press != 0) + __CtrlButtonDown(press); } void InitPadLayout(float xres, float yres, float globalScale) { @@ -890,17 +896,16 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, bool showPau return root; } - -void GestureGamepad::Touch(const TouchInput &input) { +bool GestureGamepad::Touch(const TouchInput &input) { if (usedPointerMask & (1 << input.id)) { if (input.id == dragPointerId_) dragPointerId_ = -1; - return; + return false; } if (input.flags & TOUCH_RELEASE_ALL) { dragPointerId_ = -1; - return; + return false; } if (input.flags & TOUCH_DOWN) { @@ -912,7 +917,7 @@ void GestureGamepad::Touch(const TouchInput &input) { const float now = time_now_d(); if (now - lastTapRelease_ < 0.3f && !haveDoubleTapped_) { if (g_Config.iDoubleTapGesture != 0 ) - controllMapper_->pspKey(GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_DOWN); haveDoubleTapped_ = true; } @@ -935,11 +940,12 @@ void GestureGamepad::Touch(const TouchInput &input) { if (haveDoubleTapped_) { if (g_Config.iDoubleTapGesture != 0) - controllMapper_->pspKey(GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_UP); haveDoubleTapped_ = false; } } } + return true; } void GestureGamepad::Update() { @@ -948,37 +954,37 @@ void GestureGamepad::Update() { float dy = deltaY_ * g_dpi_scale_y * g_Config.fSwipeSensitivity; if (g_Config.iSwipeRight != 0) { if (dx > th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN); swipeRightReleased_ = false; } else if (!swipeRightReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeRight-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_UP); swipeRightReleased_ = true; } } if (g_Config.iSwipeLeft != 0) { if (dx < -th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_DOWN); swipeLeftReleased_ = false; } else if (!swipeLeftReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_UP); swipeLeftReleased_ = true; } } if (g_Config.iSwipeUp != 0) { if (dy < -th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeUp-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeUp-1], KEY_DOWN); swipeUpReleased_ = false; } else if (!swipeUpReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeUp-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeUp-1], KEY_UP); swipeUpReleased_ = true; } } if (g_Config.iSwipeDown != 0) { if (dy > th) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeDown-1], KEY_DOWN); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeDown-1], KEY_DOWN); swipeDownReleased_ = false; } else if (!swipeDownReleased_) { - controllMapper_->pspKey(GestureKey::keyList[g_Config.iSwipeDown-1], KEY_UP); + controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeDown-1], KEY_UP); swipeDownReleased_ = true; } } diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index 978425cd4d..9ec5d96556 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -29,7 +29,7 @@ class GamepadView : public UI::View { public: GamepadView(const char *key, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; bool Key(const KeyInput &input) override { return false; } @@ -50,7 +50,7 @@ public: : GamepadView(key, layoutParams), scale_(scale), bgImg_(bgImg), bgDownImg_(bgDownImg), img_(img) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; virtual bool IsDown() { return pointerDownMask_ != 0; } @@ -78,7 +78,7 @@ public: : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), value_(value) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; bool IsDown() override { return *value_; } UI::Event OnChange; @@ -92,7 +92,7 @@ public: PSPButton(int pspButtonBit, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; bool IsDown() override; private: @@ -103,7 +103,7 @@ class PSPDpad : public GamepadView { public: PSPDpad(ImageID arrowIndex, const char *key, ImageID arrowDownIndex, ImageID overlayIndex, float scale, float spacing, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -124,7 +124,7 @@ class PSPStick : public GamepadView { public: PSPStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, int stick, float scale, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -149,7 +149,7 @@ class PSPCustomStick : public PSPStick { public: PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, float scale, UI::LayoutParams *layoutParams); - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; private: @@ -170,9 +170,9 @@ const int baseActionButtonSpacing = 60; class ComboKey : public MultiTouchButton { public: ComboKey(uint64_t pspButtonBit, const char *key, bool toggle, bool repeat, ControlMapper* controllMapper, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, bool invertedContextDimension, UI::LayoutParams *layoutParams) - : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle), repeat_(repeat), controllMapper_(controllMapper), on_(false), invertedContextDimension_(invertedContextDimension) { + : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle), repeat_(repeat), controlMapper_(controllMapper), on_(false), invertedContextDimension_(invertedContextDimension) { } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; bool IsDown() override; @@ -182,16 +182,16 @@ private: bool toggle_; bool repeat_; int pressedFrames_ = 0; - ControlMapper* controllMapper_; + ControlMapper* controlMapper_; bool on_; bool invertedContextDimension_; // Swap width and height }; class GestureGamepad : public UI::View { public: - GestureGamepad(ControlMapper* controllMapper) : controllMapper_(controllMapper) {}; + GestureGamepad(ControlMapper* controllMapper) : controlMapper_(controllMapper) {}; - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void Update() override; protected: @@ -208,7 +208,7 @@ protected: bool swipeUpReleased_ = true; bool swipeDownReleased_ = true; bool haveDoubleTapped_ = false; - ControlMapper* controllMapper_; + ControlMapper* controlMapper_; }; // Just edit this to add new image, shape or button function @@ -247,6 +247,13 @@ namespace CustomKey { { ImageID("I_ARROW"), 0.0f}, { ImageID("I_ARROW"), 180.0f}, { ImageID("I_GEAR"), 0.0f}, + { ImageID("I_ROTATE_LEFT"), 0.0f}, + { ImageID("I_ROTATE_RIGHT"), 0.0f}, + { ImageID("I_ARROW_LEFT"), 0.0f}, + { ImageID("I_ARROW_RIGHT"), 0.0f}, + { ImageID("I_ARROW_UP"), 0.0f}, + { ImageID("I_ARROW_DOWN"), 0.0f}, + { ImageID("I_THREE_DOTS"), 0.0f}, }; // Shape list diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index 140b82fec2..b877595d57 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -27,13 +27,13 @@ class InstallZipScreen : public UIDialogScreenWithBackground { public: InstallZipScreen(const Path &zipPath); - virtual void update() override; - virtual bool key(const KeyInput &key) override; + void update() override; + bool key(const KeyInput &key) override; const char *tag() const override { return "InstallZip"; } protected: - virtual void CreateViews() override; + void CreateViews() override; private: UI::EventReturn OnInstall(UI::EventParams ¶ms); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index d5ed3ab0a4..5a03804908 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -136,8 +136,8 @@ public: void SetHoldEnabled(bool hold) { holdEnabled_ = hold; } - void Touch(const TouchInput &input) override { - UI::Clickable::Touch(input); + bool Touch(const TouchInput &input) override { + bool retval = UI::Clickable::Touch(input); hovering_ = bounds_.Contains(input.x, input.y); if (hovering_ && (input.flags & TOUCH_DOWN)) { holdStart_ = time_now_d(); @@ -145,6 +145,7 @@ public: if (input.flags & TOUCH_UP) { holdStart_ = 0; } + return retval; } bool Key(const KeyInput &key) override { @@ -433,7 +434,7 @@ public: DirButton(const Path &path, const std::string &text, bool gridStyle, UI::LayoutParams *layoutParams = 0) : UI::Button(text, layoutParams), path_(path), gridStyle_(gridStyle), absolute_(true) {} - virtual void Draw(UIContext &dc); + void Draw(UIContext &dc) override; const Path &GetPath() const { return path_; @@ -965,7 +966,6 @@ UI::EventReturn GameBrowser::OnHomebrewStore(UI::EventParams &e) { MainScreen::MainScreen() { System_SendMessage("event", "mainscreen"); g_BackgroundAudio.SetGame(Path()); - lastVertical_ = UseVerticalLayout(); } MainScreen::~MainScreen() { @@ -1127,7 +1127,7 @@ void MainScreen::CreateViews() { #endif rightColumnItems->Add(logos); - TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0)))); + TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -10, 0, 4)))); ver->SetSmall(true); ver->SetClip(false); @@ -1254,15 +1254,6 @@ void MainScreen::sendMessage(const char *message, const char *value) { void MainScreen::update() { UIScreen::update(); UpdateUIState(UISTATE_MENU); - bool vertical = UseVerticalLayout(); - if (vertical != lastVertical_) { - RecreateViews(); - lastVertical_ = vertical; - } -} - -bool MainScreen::UseVerticalLayout() const { - return dp_yres > dp_xres * 1.1f; } UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) { @@ -1499,7 +1490,7 @@ void UmdReplaceScreen::CreateViews() { tabAllGames->OnHoldChoice.Handle(this, &UmdReplaceScreen::OnGameSelected); - rightColumnItems->Add(new Choice(di->T("Cancel")))->OnClick.Handle(this, &UmdReplaceScreen::OnCancel); + rightColumnItems->Add(new Choice(di->T("Cancel")))->OnClick.Handle(this, &UIScreen::OnCancel); rightColumnItems->Add(new Choice(mm->T("Game Settings")))->OnClick.Handle(this, &UmdReplaceScreen::OnGameSettings); if (g_Config.HasRecentIsos()) { @@ -1524,11 +1515,6 @@ UI::EventReturn UmdReplaceScreen::OnGameSelected(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn UmdReplaceScreen::OnCancel(UI::EventParams &e) { - TriggerFinish(DR_CANCEL); - return UI::EVENT_DONE; -} - UI::EventReturn UmdReplaceScreen::OnGameSettings(UI::EventParams &e) { screenManager()->push(new GameSettingsScreen(Path())); return UI::EVENT_DONE; diff --git a/UI/MainScreen.h b/UI/MainScreen.h index b81e193b93..ee79725fd1 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -114,7 +114,6 @@ protected: void sendMessage(const char *message, const char *value) override; void dialogFinished(const Screen *dialog, DialogResult result) override; - bool UseVerticalLayout() const; bool DrawBackgroundFor(UIContext &dc, const Path &gamePath, float progress); UI::EventReturn OnGameSelected(UI::EventParams &e); @@ -166,7 +165,6 @@ private: UI::EventReturn OnGameSelected(UI::EventParams &e); UI::EventReturn OnGameSelectedInstant(UI::EventParams &e); - UI::EventReturn OnCancel(UI::EventParams &e); UI::EventReturn OnGameSettings(UI::EventParams &e); }; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index d90d92f76d..d1dbb2dd1b 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -43,6 +43,7 @@ #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/HLE/sceUtility.h" #include "GPU/GPUState.h" +#include "GPU/GPUInterface.h" #include "GPU/Common/PostShader.h" #include "UI/ControlMappingScreen.h" @@ -156,7 +157,6 @@ public: class FloatingSymbolsAnimation : public Animation { public: - ~FloatingSymbolsAnimation() override {} void Draw(UIContext &dc, double t, float alpha, float x, float y, float z) override { float xres = dc.GetBounds().w; float yres = dc.GetBounds().h; @@ -195,7 +195,6 @@ private: class RecentGamesAnimation : public Animation { public: - ~RecentGamesAnimation() override {} void Draw(UIContext &dc, double t, float alpha, float x, float y, float z) override { if (lastIndex_ == nextIndex_) { CheckNext(dc, t); @@ -355,7 +354,40 @@ void DrawBackground(UIContext &dc, float alpha, float x, float y, float z) { } } -void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z) { +uint32_t GetBackgroundColorWithAlpha(const UIContext &dc) { + return colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); // 0.65 = 166 = A6 +} + +void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z, bool darkenBackground) { + using namespace Draw; + using namespace UI; + + if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { + gpu->CheckDisplayResized(); + gpu->CheckConfigChanged(); + gpu->CopyDisplayToOutput(true); + + DrawContext *draw = dc.GetDrawContext(); + Viewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = pixel_xres; + viewport.Height = pixel_yres; + viewport.MaxDepth = 1.0; + viewport.MinDepth = 0.0; + draw->SetViewports(1, &viewport); + dc.BeginFrame(); + dc.RebindTexture(); + dc.Begin(); + + if (darkenBackground) { + uint32_t color = GetBackgroundColorWithAlpha(dc); + dc.FillRect(UI::Drawable(color), dc.GetBounds()); + dc.Flush(); + } + return; + } + std::shared_ptr ginfo; if (!gamePath.empty()) ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath, GAMEINFO_WANTBG); @@ -364,8 +396,6 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f GameInfoTex *pic = ginfo ? ginfo->GetBGPic() : nullptr; if (pic) { dc.GetDrawContext()->BindTexture(0, pic->texture->GetTexture()); - } - if (pic) { uint32_t color = whiteAlpha(ease((time_now_d() - pic->timeLoaded) * 3)) & 0xFFc0c0c0; dc.Draw()->DrawTexRect(dc.GetBounds(), 0,0,1,1, color); dc.Flush(); @@ -377,7 +407,7 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f } } -void HandleCommonMessages(const char *message, const char *value, ScreenManager *manager, Screen *activeScreen) { +void HandleCommonMessages(const char *message, const char *value, ScreenManager *manager, const Screen *activeScreen) { bool isActiveScreen = manager->topScreen() == activeScreen; if (!strcmp(message, "clear jit") && PSP_IsInited()) { @@ -389,16 +419,16 @@ void HandleCommonMessages(const char *message, const char *value, ScreenManager currentMIPS->UpdateCore((CPUCore)g_Config.iCpuCore); } else if (!strcmp(message, "control mapping") && isActiveScreen && std::string(activeScreen->tag()) != "ControlMapping") { UpdateUIState(UISTATE_MENU); - manager->push(new ControlMappingScreen()); + manager->push(new ControlMappingScreen(Path())); } else if (!strcmp(message, "display layout editor") && isActiveScreen && std::string(activeScreen->tag()) != "DisplayLayout") { UpdateUIState(UISTATE_MENU); - manager->push(new DisplayLayoutScreen()); + manager->push(new DisplayLayoutScreen(Path())); } else if (!strcmp(message, "settings") && isActiveScreen && std::string(activeScreen->tag()) != "GameSettings") { UpdateUIState(UISTATE_MENU); manager->push(new GameSettingsScreen(Path())); } else if (!strcmp(message, "language screen") && isActiveScreen) { - auto dev = GetI18NCategory("Developer"); - auto langScreen = new NewLanguageScreen(dev->T("Language")); + auto sy = GetI18NCategory("System"); + auto langScreen = new NewLanguageScreen(sy->T("Language")); langScreen->OnChoice.Add([](UI::EventParams &) { NativeMessageReceived("recreateviews", ""); if (host) { @@ -427,7 +457,7 @@ void UIScreenWithGameBackground::DrawBackground(UIContext &dc) { float x, y, z; screenManager()->getFocusPosition(x, y, z); if (!gamePath_.empty()) { - DrawGameBackground(dc, gamePath_, x, y, z); + DrawGameBackground(dc, gamePath_, x, y, z, darkenGameBackground_); } else { ::DrawBackground(dc, 1.0f, x, y, z); dc.Flush(); @@ -443,9 +473,11 @@ void UIScreenWithGameBackground::sendMessage(const char *message, const char *va } void UIDialogScreenWithGameBackground::DrawBackground(UIContext &dc) { + using namespace UI; + using namespace Draw; float x, y, z; screenManager()->getFocusPosition(x, y, z); - DrawGameBackground(dc, gamePath_, x, y, z); + DrawGameBackground(dc, gamePath_, x, y, z, darkenGameBackground_); } void UIDialogScreenWithGameBackground::sendMessage(const char *message, const char *value) { @@ -477,8 +509,8 @@ void UIDialogScreenWithBackground::sendMessage(const char *message, const char * HandleCommonMessages(message, value, screenManager(), this); } -PromptScreen::PromptScreen(std::string message, std::string yesButtonText, std::string noButtonText, std::function callback) - : message_(message), callback_(callback) { +PromptScreen::PromptScreen(const Path &gamePath, std::string message, std::string yesButtonText, std::string noButtonText, std::function callback) + : UIDialogScreenWithGameBackground(gamePath), message_(message), callback_(callback) { auto di = GetI18NCategory("Dialog"); yesButtonText_ = di->T(yesButtonText.c_str()); noButtonText_ = di->T(noButtonText.c_str()); @@ -521,36 +553,6 @@ void PromptScreen::TriggerFinish(DialogResult result) { UIDialogScreenWithBackground::TriggerFinish(result); } -PostProcScreen::PostProcScreen(const std::string &title, int id) : ListPopupScreen(title), id_(id) { } - -void PostProcScreen::CreateViews() { - auto ps = GetI18NCategory("PostShaders"); - ReloadAllPostShaderInfo(screenManager()->getDrawContext()); - shaders_ = GetAllPostShaderInfo(); - std::vector items; - int selected = -1; - const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; - for (int i = 0; i < (int)shaders_.size(); i++) { - if (!shaders_[i].visible) - continue; - if (shaders_[i].section == selectedName) - selected = i; - items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); - } - adaptor_ = UI::StringVectorListAdaptor(items, selected); - ListPopupScreen::CreateViews(); -} - -void PostProcScreen::OnCompleted(DialogResult result) { - if (result != DR_OK) - return; - const std::string &value = shaders_[listView_->GetSelected()].section; - if (id_ < (int)g_Config.vPostShaderNames.size()) - g_Config.vPostShaderNames[id_] = value; - else - g_Config.vPostShaderNames.push_back(value); -} - TextureShaderScreen::TextureShaderScreen(const std::string &title) : ListPopupScreen(title) {} void TextureShaderScreen::CreateViews() { @@ -580,7 +582,7 @@ NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen #ifdef _MSC_VER #pragma warning(disable:4566) #endif - langValuesMapping = GetLangValuesMapping(); + auto &langValuesMapping = g_Config.GetLangValuesMapping(); std::vector tempLangs; VFSGetFileListing("lang", &tempLangs, "ini"); @@ -616,11 +618,12 @@ NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen std::string buttonTitle = lang.name; if (!code.empty()) { - if (langValuesMapping.find(code) == langValuesMapping.end()) { + auto iter = langValuesMapping.find(code); + if (iter == langValuesMapping.end()) { // No title found, show locale code buttonTitle = code; } else { - buttonTitle = langValuesMapping[code].first; + buttonTitle = iter->second.first; } } if (g_Config.sLanguageIni == code) @@ -661,11 +664,14 @@ void NewLanguageScreen::OnCompleted(DialogResult result) { if (iniLoadedSuccessfully) { // Dunno what else to do here. - if (langValuesMapping.find(code) == langValuesMapping.end()) { + auto &langValuesMapping = g_Config.GetLangValuesMapping(); + + auto iter = langValuesMapping.find(code); + if (iter == langValuesMapping.end()) { // Fallback to English g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; } else { - g_Config.iLanguage = langValuesMapping[code].second; + g_Config.iLanguage = iter->second.second; } RecreateViews(); } else { @@ -804,7 +810,7 @@ void CreditsScreen::CreateViews() { root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); Button *back = root_->Add(new Button(di->T("Back"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 10, false))); - back->OnClick.Handle(this, &CreditsScreen::OnOK); + back->OnClick.Handle(this, &UIScreen::OnOK); root_->SetDefaultFocusView(back); // Really need to redo this whole layout with some linear layouts... @@ -873,11 +879,6 @@ UI::EventReturn CreditsScreen::OnShare(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn CreditsScreen::OnOK(UI::EventParams &e) { - TriggerFinish(DR_OK); - return UI::EVENT_DONE; -} - CreditsScreen::CreditsScreen() { startTime_ = time_now_d(); } @@ -1069,7 +1070,7 @@ SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp) Add(new UI::Spacer(10.0f)); } -void SettingInfoMessage::Show(const std::string &text, UI::View *refView) { +void SettingInfoMessage::Show(const std::string &text, const UI::View *refView) { if (refView) { Bounds b = refView->GetBounds(); const UI::AnchorLayoutParams *lp = GetLayoutParams()->As(); diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 164a06cfec..f91cfa6bfe 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -51,6 +51,8 @@ public: void sendMessage(const char *message, const char *value) override; protected: Path gamePath_; + + bool darkenGameBackground_ = false; }; class UIDialogScreenWithBackground : public UIDialogScreen { @@ -71,11 +73,12 @@ public: void sendMessage(const char *message, const char *value) override; protected: Path gamePath_; + bool darkenGameBackground_ = true; }; -class PromptScreen : public UIDialogScreenWithBackground { +class PromptScreen : public UIDialogScreenWithGameBackground { public: - PromptScreen(std::string message, std::string yesButtonText, std::string noButtonText, + PromptScreen(const Path& gamePath, std::string message, std::string yesButtonText, std::string noButtonText, std::function callback = &NoOpVoidBool); void CreateViews() override; @@ -103,26 +106,9 @@ public: private: void OnCompleted(DialogResult result) override; bool ShowButtons() const override { return true; } - std::map> langValuesMapping; - std::map titleCodeMapping; std::vector langs_; }; -class PostProcScreen : public ListPopupScreen { -public: - PostProcScreen(const std::string &title, int id); - - void CreateViews() override; - - const char *tag() const override { return "PostProc"; } - -private: - void OnCompleted(DialogResult result) override; - bool ShowButtons() const override { return true; } - std::vector shaders_; - int id_; -}; - class TextureShaderScreen : public ListPopupScreen { public: TextureShaderScreen(const std::string &title); @@ -175,8 +161,6 @@ public: const char *tag() const override { return "Credits"; } private: - UI::EventReturn OnOK(UI::EventParams &e); - UI::EventReturn OnSupport(UI::EventParams &e); UI::EventReturn OnPPSSPPOrg(UI::EventParams &e); UI::EventReturn OnPrivacy(UI::EventParams &e); @@ -195,9 +179,9 @@ public: void SetBottomCutoff(float y) { cutOffY_ = y; } - void Show(const std::string &text, UI::View *refView = nullptr); + void Show(const std::string &text, const UI::View *refView = nullptr); - void Draw(UIContext &dc); + void Draw(UIContext &dc) override; std::string GetText() const; private: @@ -206,3 +190,5 @@ private: float cutOffY_; bool showing_ = false; }; + +uint32_t GetBackgroundColorWithAlpha(const UIContext &dc); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 93b11fd53e..9d127c155a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -114,7 +114,6 @@ #include "UI/OnScreenDisplay.h" #include "UI/RemoteISOScreen.h" #include "UI/TiltEventProcessor.h" -#include "UI/TextureUtil.h" #include "UI/Theme.h" #if !defined(MOBILE_DEVICE) && defined(USING_QT_UI) @@ -827,7 +826,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch screenManager->switchScreen(new LogoScreen(AfterLogoScreen::TO_GAME_SETTINGS)); } else if (gotoTouchScreenTest) { screenManager->switchScreen(new MainScreen()); - screenManager->push(new TouchTestScreen()); + screenManager->push(new TouchTestScreen(Path())); } else if (skipLogo) { screenManager->switchScreen(new EmuScreen(boot_filename)); } else { @@ -934,6 +933,16 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { bool CreateGlobalPipelines() { using namespace Draw; + ShaderModule *vs_color_2d = g_draw->GetVshaderPreset(VS_COLOR_2D); + ShaderModule *fs_color_2d = g_draw->GetFshaderPreset(FS_COLOR_2D); + ShaderModule *vs_texture_color_2d = g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D); + ShaderModule *fs_texture_color_2d = g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D); + + if (!vs_color_2d || !fs_color_2d || !vs_texture_color_2d || !fs_texture_color_2d) { + ERROR_LOG(G3D, "Failed to get shader preset"); + return false; + } + InputLayout *inputLayout = ui_draw2d.CreateInputLayout(g_draw); BlendState *blendNormal = g_draw->CreateBlendState({ true, 0xF, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA }); DepthStencilState *depth = g_draw->CreateDepthStencilState({ false, false, Comparison::LESS }); @@ -941,12 +950,12 @@ bool CreateGlobalPipelines() { PipelineDesc colorDesc{ Primitive::TRIANGLE_LIST, - { g_draw->GetVshaderPreset(VS_COLOR_2D), g_draw->GetFshaderPreset(FS_COLOR_2D) }, + { vs_color_2d, fs_color_2d }, inputLayout, depth, blendNormal, rasterNoCull, &vsColBufDesc, }; PipelineDesc texColorDesc{ Primitive::TRIANGLE_LIST, - { g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, + { vs_texture_color_2d, fs_texture_color_2d }, inputLayout, depth, blendNormal, rasterNoCull, &vsTexColBufDesc, }; @@ -1055,7 +1064,7 @@ void TakeScreenshot() { } void RenderOverlays(UIContext *dc, void *userdata) { - // Thin bar at the top of the screen like Chrome. + // Thin bar at the top of the screen. std::vector progress = g_DownloadManager.GetCurrentProgress(); if (!progress.empty()) { static const uint32_t colors[4] = { @@ -1082,8 +1091,8 @@ void RenderOverlays(UIContext *dc, void *userdata) { } void NativeRender(GraphicsContext *graphicsContext) { - _assert_(graphicsContext != nullptr); - _assert_(screenManager != nullptr); + _dbg_assert_(graphicsContext != nullptr); + _dbg_assert_(screenManager != nullptr); g_GameManager.Update(); @@ -1158,7 +1167,7 @@ void NativeRender(GraphicsContext *graphicsContext) { #if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID) PSP_CoreParameter().pixelWidth = pixel_xres; PSP_CoreParameter().pixelHeight = pixel_yres; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); #endif } else { // INFO_LOG(G3D, "Polling graphics context"); @@ -1179,10 +1188,10 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { if (msg == "inputDeviceConnectedID") { nextInputDeviceID = parseLong(value); } - if (msg == "inputDeviceConnected") { + else if (msg == "inputDeviceConnected") { KeyMap::NotifyPadConnected(nextInputDeviceID, value); } - if (msg == "bgImage_updated") { + else if (msg == "bgImage_updated") { if (!value.empty()) { Path dest = GetSysDirectory(DIRECTORY_SYSTEM) / (endsWithNoCase(value, ".jpg") ? "background.jpg" : "background.png"); File::Copy(Path(value), dest); @@ -1190,20 +1199,29 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { UIBackgroundShutdown(); // It will init again automatically. We can't init outside a frame on Vulkan. } - if (msg == "savestate_displayslot") { + else if (msg == "savestate_displayslot") { auto sy = GetI18NCategory("System"); std::string msg = StringFromFormat("%s: %d", sy->T("Savestate Slot"), SaveState::GetCurrentSlot() + 1); // Show for the same duration as the preview. osm.Show(msg, 2.0f, 0xFFFFFF, -1, true, "savestate_slot"); } - if (msg == "gpu_resized" || msg == "gpu_clearCache") { + else if (msg == "gpu_displayResized") { if (gpu) { - gpu->ClearCacheNextFrame(); - gpu->Resized(); + gpu->NotifyDisplayResized(); + } + } + else if (msg == "gpu_renderResized") { + if (gpu) { + gpu->NotifyRenderResized(); + } + } + else if (msg == "gpu_configChanged") { + if (gpu) { + gpu->NotifyConfigChanged(); } Reporting::UpdateConfig(); } - if (msg == "core_powerSaving") { + else if (msg == "core_powerSaving") { if (value != "false") { auto sy = GetI18NCategory("System"); #if PPSSPP_PLATFORM(ANDROID) @@ -1214,7 +1232,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { } Core_SetPowerSaving(value != "false"); } - if (msg == "permission_granted" && value == "storage") { + else if (msg == "permission_granted" && value == "storage") { #if PPSSPP_PLATFORM(ANDROID) CreateDirectoriesAndroid(); #endif @@ -1230,7 +1248,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { PostLoadConfig(); g_Config.iGPUBackend = gpuBackend; } - if (msg == "app_resumed" || msg == "got_focus") { + else if (msg == "app_resumed" || msg == "got_focus") { // Assume that the user may have modified things. MemoryStick_NotifyWrite(); } @@ -1296,10 +1314,9 @@ bool NativeTouch(const TouchInput &touch) { } bool NativeKey(const KeyInput &key) { - - // Hack to quickly enable 2D mode in VR game mode. - if (IsVRBuild()) { - UpdateVRScreenKey(key); + // VR actions + if (IsVREnabled() && !UpdateVRKeys(key)) { + return false; } // INFO_LOG(SYSTEM, "Key code: %i flags: %i", key.keyCode, key.flags); @@ -1322,6 +1339,11 @@ bool NativeKey(const KeyInput &key) { } bool NativeAxis(const AxisInput &axis) { + // VR actions + if (IsVREnabled() && !UpdateVRAxis(axis)) { + return false; + } + if (!screenManager) { // Too early. return false; @@ -1331,7 +1353,7 @@ bool NativeAxis(const AxisInput &axis) { // only handle tilt events if tilt is enabled. if (g_Config.iTiltInputType == TILT_NULL) { - // if tilt events are disabled, then run it through the usual way. + // if tilt events are disabled, then run it through the usual way. if (screenManager) { return screenManager->axis(axis); } else { @@ -1397,7 +1419,7 @@ bool NativeAxis(const AxisInput &axis) { currentTilt.y_ = -axis.value; } break; - + case JOYSTICK_AXIS_OUYA_UNKNOWN1: case JOYSTICK_AXIS_OUYA_UNKNOWN2: case JOYSTICK_AXIS_OUYA_UNKNOWN3: @@ -1409,6 +1431,8 @@ bool NativeAxis(const AxisInput &axis) { default: // Don't take over completely! + if (!screenManager) + return false; return screenManager->axis(axis); } @@ -1419,7 +1443,7 @@ bool NativeAxis(const AxisInput &axis) { //then a value of 70-80 is the way to go. float xSensitivity = g_Config.iTiltSensitivityX / 50.0; float ySensitivity = g_Config.iTiltSensitivityY / 50.0; - + //now transform out current tilt to the calibrated coordinate system Tilt trueTilt = GenTilt(baseTilt, currentTilt, g_Config.bInvertTiltX, g_Config.bInvertTiltY, g_Config.fDeadzoneRadius, xSensitivity, ySensitivity); diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 748fcdf86d..d76824d9b1 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -28,6 +28,8 @@ #include "Common/Data/Text/I18n.h" #include "Common/StringUtils.h" #include "Common/System/System.h" +#include "Common/VR/PPSSPPVR.h" +#include "Common/UI/AsyncImageFileView.h" #include "Core/Reporting.h" #include "Core/SaveState.h" @@ -47,115 +49,7 @@ #include "UI/MainScreen.h" #include "UI/OnScreenDisplay.h" #include "UI/GameInfoCache.h" - -AsyncImageFileView::AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams) - : UI::Clickable(layoutParams), canFocus_(true), filename_(filename), color_(0xFFFFFFFF), sizeMode_(sizeMode), textureFailed_(false), fixedSizeW_(0.0f), fixedSizeH_(0.0f) {} - -AsyncImageFileView::~AsyncImageFileView() {} - -static float DesiredSize(float sz, float contentSize, UI::MeasureSpec spec) { - float measured; - UI::MeasureBySpec(sz, contentSize, spec, &measured); - return measured; -} - -void AsyncImageFileView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const { - if (texture_ && texture_->GetTexture()) { - float texw = (float)texture_->Width(); - float texh = (float)texture_->Height(); - float desiredW = DesiredSize(layoutParams_->width, w, horiz); - float desiredH = DesiredSize(layoutParams_->height, h, vert); - switch (sizeMode_) { - case UI::IS_FIXED: - w = fixedSizeW_; - h = fixedSizeH_; - break; - case UI::IS_KEEP_ASPECT: - w = texw; - h = texh; - if (desiredW != w || desiredH != h) { - float aspect = w / h; - // We need the other dimension based on the desired scale to find the best aspect. - float desiredWOther = DesiredSize(layoutParams_->height, h * (desiredW / w), vert); - float desiredHOther = DesiredSize(layoutParams_->width, w * (desiredH / h), horiz); - - float diffW = fabsf(aspect - desiredW / desiredWOther); - float diffH = fabsf(aspect - desiredH / desiredHOther); - if (diffW < diffH) { - w = desiredW; - h = desiredWOther; - } else { - w = desiredHOther; - h = desiredH; - } - } - break; - case UI::IS_DEFAULT: - default: - w = texw; - h = texh; - break; - } - } else { - w = 16; - h = 16; - } -} - -void AsyncImageFileView::SetFilename(const Path &filename) { - if (filename_ != filename) { - textureFailed_ = false; - filename_ = filename; - texture_.reset(nullptr); - } -} - -void AsyncImageFileView::DeviceLost() { - if (texture_.get()) - texture_->DeviceLost(); -} - -void AsyncImageFileView::DeviceRestored(Draw::DrawContext *draw) { - if (texture_.get()) - texture_->DeviceRestored(draw); -} - -void AsyncImageFileView::Draw(UIContext &dc) { - using namespace Draw; - if (!texture_ && !textureFailed_ && !filename_.empty()) { - texture_ = CreateTextureFromFile(dc.GetDrawContext(), filename_.c_str(), DETECT, true); - if (!texture_.get()) - textureFailed_ = true; - } - - if (HasFocus()) { - dc.FillRect(dc.theme->itemFocusedStyle.background, bounds_.Expand(3)); - } - - // TODO: involve sizemode - if (texture_ && texture_->GetTexture()) { - dc.Flush(); - dc.GetDrawContext()->BindTexture(0, texture_->GetTexture()); - dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); - dc.Flush(); - dc.RebindTexture(); - if (!text_.empty()) { - dc.DrawText(text_.c_str(), bounds_.centerX()+1, bounds_.centerY()+1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - } - } else { - if (!filename_.empty()) { - // draw a black rectangle to represent the missing screenshot. - dc.FillRect(UI::Drawable(0xFF000000), GetBounds()); - } else { - // draw a dark gray rectangle to represent no save state. - dc.FillRect(UI::Drawable(0x50202020), GetBounds()); - } - if (!text_.empty()) { - dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - } - } -} +#include "UI/DisplayLayoutScreen.h" static void AfterSaveStateAction(SaveState::Status status, const std::string &message, void *) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { @@ -238,7 +132,7 @@ UI::EventReturn ScreenshotViewScreen::OnUndoState(UI::EventParams &e) { class SaveSlotView : public UI::LinearLayout { public: - SaveSlotView(const Path &gamePath, int slot, UI::LayoutParams *layoutParams = nullptr); + SaveSlotView(const Path &gamePath, int slot, bool vertical, UI::LayoutParams *layoutParams = nullptr); void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { w = 500; h = 90; @@ -275,7 +169,7 @@ private: Path screenshotFilename_; }; -SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), slot_(slot), gamePath_(gameFilename) { +SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, bool vertical, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), slot_(slot), gamePath_(gameFilename) { using namespace UI; screenshotFilename_ = SaveState::GenerateSaveSlotFilename(gamePath_, slot, SaveState::SCREENSHOT_EXTENSION); @@ -286,9 +180,15 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams auto pa = GetI18NCategory("Pause"); - LinearLayout *buttons = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - buttons->SetSpacing(2.0); - Add(buttons); + LinearLayout *lines = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + lines->SetSpacing(2.0f); + + Add(lines); + + LinearLayout *buttons = new LinearLayout(vertical ? ORIENT_VERTICAL : ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + buttons->SetSpacing(10.0f); + + lines->Add(buttons); saveStateButton_ = buttons->Add(new Button(pa->T("Save State"), new LinearLayoutParams(0.0, G_VCENTER))); saveStateButton_->OnClick.Handle(this, &SaveSlotView::OnSaveState); @@ -300,14 +200,12 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, UI::LayoutParams loadStateButton_->OnClick.Handle(this, &SaveSlotView::OnLoadState); std::string dateStr = SaveState::GetSlotDateAsString(gamePath_, slot_); - std::vector dateStrs; - SplitString(dateStr, ' ', dateStrs); - if (!dateStrs.empty() && !dateStrs[0].empty()) { - LinearLayout *strs = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - Add(strs); - for (size_t i = 0; i < dateStrs.size(); i++) { - strs->Add(new TextView(dateStrs[i], new LinearLayoutParams(0.0, G_VCENTER)))->SetShadow(true); + if (!dateStr.empty()) { + TextView *dateView = new TextView(dateStr, new LinearLayoutParams(0.0, G_VCENTER)); + if (vertical) { + dateView->SetSmall(true); } + lines->Add(dateView)->SetShadow(true); } } else { fv->SetFilename(Path()); @@ -355,6 +253,8 @@ void GamePauseScreen::update() { TriggerFinish(DR_CANCEL); finishNextFrame_ = false; } + + SetVRAppMode(VRAppMode::VR_MENU_MODE); } GamePauseScreen::~GamePauseScreen() { @@ -365,6 +265,9 @@ void GamePauseScreen::CreateViews() { static const int NUM_SAVESLOTS = 5; using namespace UI; + + bool vertical = UseVerticalLayout(); + Margins scrollMargins(0, 20, 0, 0); Margins actionMenuMargins(0, 20, 15, 0); auto gr = GetI18NCategory("Graphics"); @@ -381,7 +284,7 @@ void GamePauseScreen::CreateViews() { leftColumnItems->Add(new Spacer(0.0)); leftColumnItems->SetSpacing(10.0); for (int i = 0; i < NUM_SAVESLOTS; i++) { - SaveSlotView *slot = leftColumnItems->Add(new SaveSlotView(gamePath_, i, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); + SaveSlotView *slot = leftColumnItems->Add(new SaveSlotView(gamePath_, i, vertical, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); slot->OnStateLoaded.Handle(this, &GamePauseScreen::OnState); slot->OnStateSaved.Handle(this, &GamePauseScreen::OnState); slot->OnScreenshotClicked.Handle(this, &GamePauseScreen::OnScreenshotClicked); @@ -405,7 +308,7 @@ void GamePauseScreen::CreateViews() { rewindButton->OnClick.Handle(this, &GamePauseScreen::OnRewind); } - ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); + ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(vertical ? 200 : 300, FILL_PARENT, actionMenuMargins)); root_->Add(rightColumn); LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL); @@ -419,6 +322,8 @@ void GamePauseScreen::CreateViews() { root_->SetDefaultFocusView(continueChoice); continueChoice->OnClick.Handle(this, &UIScreen::OnBack); + rightColumnItems->Add(new Spacer(25.0)); + std::string gameId = g_paramSFO.GetDiscID(); if (g_Config.hasGameConfig(gameId)) { rightColumnItems->Add(new Choice(pa->T("Game Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); @@ -427,6 +332,11 @@ void GamePauseScreen::CreateViews() { rightColumnItems->Add(new Choice(pa->T("Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); rightColumnItems->Add(new Choice(pa->T("Create Game Config")))->OnClick.Handle(this, &GamePauseScreen::OnCreateConfig); } + UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display Layout && Effects"))); + displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new DisplayLayoutScreen(gamePath_)); + return UI::EVENT_DONE; + }); if (g_Config.bEnableCheats) { rightColumnItems->Add(new Choice(pa->T("Cheats")))->OnClick.Handle(this, &GamePauseScreen::OnCwCheat); } @@ -556,7 +466,7 @@ UI::EventReturn GamePauseScreen::OnDeleteConfig(UI::EventParams &e) auto di = GetI18NCategory("Dialog"); auto ga = GetI18NCategory("Game"); screenManager()->push( - new PromptScreen(di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GamePauseScreen::CallbackDeleteConfig, this, std::placeholders::_1))); return UI::EVENT_DONE; diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 3c66609285..f9f0a949ab 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -24,20 +24,24 @@ #include "Common/UI/UIScreen.h" #include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" -#include "UI/TextureUtil.h" + +enum class PauseScreenMode { + MAIN, + DISPLAY_SETTINGS, +}; class GamePauseScreen : public UIDialogScreenWithGameBackground { public: GamePauseScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename), gamePath_(filename) {} - virtual ~GamePauseScreen(); + ~GamePauseScreen(); - virtual void dialogFinished(const Screen *dialog, DialogResult dr) override; + void dialogFinished(const Screen *dialog, DialogResult dr) override; const char *tag() const override { return "GamePause"; } protected: - virtual void CreateViews() override; - virtual void update() override; + void CreateViews() override; + void update() override; void CallbackDeleteConfig(bool yes); private: @@ -61,41 +65,5 @@ private: // hack bool finishNextFrame_ = false; Path gamePath_; -}; - -// AsyncImageFileView loads a texture from a file, and reloads it as necessary. -// TODO: Actually make async, doh. -class AsyncImageFileView : public UI::Clickable { -public: - AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams = 0); - ~AsyncImageFileView(); - - void GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const override; - void Draw(UIContext &dc) override; - std::string DescribeText() const override { return text_; } - - void DeviceLost() override; - void DeviceRestored(Draw::DrawContext *draw) override; - - void SetFilename(const Path &filename); - void SetColor(uint32_t color) { color_ = color; } - void SetOverlayText(std::string text) { text_ = text; } - void SetFixedSize(float fixW, float fixH) { fixedSizeW_ = fixW; fixedSizeH_ = fixH; } - void SetCanBeFocused(bool can) { canFocus_ = can; } - - bool CanBeFocused() const override { return canFocus_; } - - const Path &GetFilename() const { return filename_; } - -private: - bool canFocus_; - Path filename_; - std::string text_; - uint32_t color_; - UI::ImageSizeMode sizeMode_; - - std::unique_ptr texture_; - bool textureFailed_; - float fixedSizeW_; - float fixedSizeH_; + PauseScreenMode mode_ = PauseScreenMode::MAIN; }; diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 7d60e507a4..93e2ae7681 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -517,11 +517,11 @@ RemoteISOBrowseScreen::RemoteISOBrowseScreen(const std::string &url, const std:: } void RemoteISOBrowseScreen::CreateViews() { - bool vertical = UseVerticalLayout(); - auto di = GetI18NCategory("Dialog"); auto ri = GetI18NCategory("RemoteISO"); + bool vertical = UseVerticalLayout(); + Margins actionMenuMargins(0, 10, 10, 0); TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); diff --git a/UI/RemoteISOScreen.h b/UI/RemoteISOScreen.h index b8676e4832..53bc2706ed 100644 --- a/UI/RemoteISOScreen.h +++ b/UI/RemoteISOScreen.h @@ -57,7 +57,7 @@ enum class ScanStatus { class RemoteISOConnectScreen : public UIScreenWithBackground { public: RemoteISOConnectScreen(); - ~RemoteISOConnectScreen() override; + ~RemoteISOConnectScreen(); const char *tag() const override { return "RemoteISOConnect"; } diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index 101ec4c83b..c192a021a5 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -20,6 +20,7 @@ // TODO: For text align flags, probably shouldn't be in gfx_es2/... #include "Common/Render/DrawBuffer.h" #include "Common/GPU/thin3d.h" +#include "Common/UI/AsyncImageFileView.h" #include "Common/UI/Context.h" #include "UI/PauseScreen.h" #include "UI/ReportScreen.h" @@ -42,7 +43,7 @@ class RatingChoice : public LinearLayout { public: RatingChoice(const char *captionKey, int *value, LayoutParams *layoutParams = 0); - RatingChoice *SetEnabledPtr(bool *enabled); + RatingChoice *SetEnabledPtrs(bool *enabled); Event OnChoice; @@ -93,7 +94,7 @@ void RatingChoice::Update() { } } -RatingChoice *RatingChoice::SetEnabledPtr(bool *ptr) { +RatingChoice *RatingChoice::SetEnabledPtrs(bool *ptr) { for (int i = 0; i < TotalChoices(); i++) { GetChoice(i)->SetEnabledPtr(ptr); } @@ -138,8 +139,8 @@ public: CompatRatingChoice(const char *captionKey, int *value, LayoutParams *layoutParams = 0); protected: - virtual void SetupChoices() override; - virtual int TotalChoices() override { + void SetupChoices() override; + int TotalChoices() override { return 5; } }; @@ -294,16 +295,16 @@ void ReportScreen::CreateViews() { screenshot_ = nullptr; } - leftColumnItems->Add(new CompatRatingChoice("Overall", (int *)&overall_))->SetEnabledPtr(&enableReporting_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + leftColumnItems->Add(new CompatRatingChoice("Overall", (int *)&overall_))->SetEnabledPtrs(&enableReporting_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); overallDescription_ = leftColumnItems->Add(new TextView("", FLAG_WRAP_TEXT, false, new LinearLayoutParams(Margins(10, 0)))); overallDescription_->SetShadow(true); UI::Orientation ratingsOrient = leftColumnWidth >= 750.0f ? ORIENT_HORIZONTAL : ORIENT_VERTICAL; UI::LinearLayout *ratingsHolder = new LinearLayoutList(ratingsOrient, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)); leftColumnItems->Add(ratingsHolder); - ratingsHolder->Add(new RatingChoice("Graphics", &graphics_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); - ratingsHolder->Add(new RatingChoice("Speed", &speed_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); - ratingsHolder->Add(new RatingChoice("Gameplay", &gameplay_))->SetEnabledPtr(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + ratingsHolder->Add(new RatingChoice("Graphics", &graphics_))->SetEnabledPtrs(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + ratingsHolder->Add(new RatingChoice("Speed", &speed_))->SetEnabledPtrs(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); + ratingsHolder->Add(new RatingChoice("Gameplay", &gameplay_))->SetEnabledPtrs(&ratingEnabled_)->OnChoice.Handle(this, &ReportScreen::HandleChoice); rightColumnItems->SetSpacing(0.0f); rightColumnItems->Add(new Choice(rp->T("Open Browser")))->OnClick.Handle(this, &ReportScreen::HandleBrowser); @@ -484,7 +485,7 @@ void ReportFinishScreen::ShowSuggestions() { const char *suggestion = nullptr; if (item == "Upgrade") { suggestion = rp->T("SuggestionUpgrade", "Upgrade to a newer PPSSPP build"); - } if (item == "Downgrade") { + } else if (item == "Downgrade") { suggestion = rp->T("SuggestionDowngrade", "Downgrade to an older PPSSPP version (please report this bug)"); } else if (item == "VerifyDisc") { suggestion = rp->T("SuggestionVerifyDisc", "Check your ISO is a good copy of your disc"); diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 0172b6a19b..0d04ac02b9 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -29,6 +29,7 @@ #include "Common/UI/Context.h" #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "Common/UI/AsyncImageFileView.h" #include "UI/SavedataScreen.h" #include "UI/MainScreen.h" #include "UI/GameInfoCache.h" @@ -707,3 +708,38 @@ void SavedataScreen::sendMessage(const char *message, const char *value) { stateBrowser_->SetSearchFilter(searchFilter_); } } + +void GameIconView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { + w = textureWidth_; + h = textureHeight_; +} + +void GameIconView::Draw(UIContext &dc) { + using namespace UI; + std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); + + if (!info->icon.texture) { + return; + } + + textureWidth_ = info->icon.texture->Width() * scale_; + textureHeight_ = info->icon.texture->Height() * scale_; + + // Fade icon with the backgrounds. + double loadTime = info->icon.timeLoaded; + auto pic = info->GetBGPic(); + if (pic) { + loadTime = std::max(loadTime, pic->timeLoaded); + } + uint32_t color = whiteAlpha(ease((time_now_d() - loadTime) * 3)); + + // Adjust size so we don't stretch the image vertically or horizontally. + // Make sure it's not wider than 144 (like Doom Legacy homebrew), ugly in the grid mode. + float nw = std::min(bounds_.h * textureWidth_ / textureHeight_, (float)bounds_.w); + + dc.Flush(); + dc.GetDrawContext()->BindTexture(0, info->icon.texture->GetTexture()); + dc.Draw()->Rect(bounds_.x, bounds_.y, nw, bounds_.h, color); + dc.Flush(); + dc.RebindTexture(); +} diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index 1bb2f42140..10cd631250 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -27,6 +27,7 @@ #include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" +#include "UI/GameInfoCache.h" enum class SavedataSortOption { FILENAME, @@ -88,3 +89,19 @@ protected: SavedataBrowser *stateBrowser_; std::string searchFilter_; }; + +class GameIconView : public UI::InertView { +public: + GameIconView(const Path &gamePath, float scale, UI::LayoutParams *layoutParams = 0) + : InertView(layoutParams), gamePath_(gamePath), scale_(scale) {} + + void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; + void Draw(UIContext &dc) override; + std::string DescribeText() const override { return ""; } + +private: + Path gamePath_; + float scale_ = 1.0f; + int textureWidth_ = 0; + int textureHeight_ = 0; +}; diff --git a/UI/Store.cpp b/UI/Store.cpp index 86a084da95..5eff6e4178 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -26,12 +26,12 @@ #include "Common/Data/Text/I18n.h" #include "Common/Data/Format/JSONReader.h" #include "Common/StringUtils.h" +#include "Common/Render/ManagedTexture.h" #include "Core/Config.h" #include "Core/System.h" #include "Core/Util/GameManager.h" #include "UI/EmuScreen.h" #include "UI/Store.h" -#include "UI/TextureUtil.h" const std::string storeBaseUrl = "http://store.ppsspp.org/"; @@ -198,7 +198,7 @@ public: StoreEntry GetEntry() const { return entry_; } private: - const StoreEntry &entry_; + const StoreEntry entry_; }; // This is a "details" view of a game. Lets you install it. @@ -403,19 +403,6 @@ void StoreScreen::update() { // Forget the listing. listing_.reset(); } - - const char *storeName = "PPSSPP Homebrew Store"; - switch (g_GameManager.GetState()) { - case GameManagerState::DOWNLOADING: - titleText_->SetText(std::string(storeName) + " - downloading"); - break; - case GameManagerState::INSTALLING: - titleText_->SetText(std::string(storeName) + " - installing"); - break; - default: - titleText_->SetText(storeName); - break; - } } void StoreScreen::ParseListing(std::string json) { @@ -441,7 +428,7 @@ void StoreScreen::ParseListing(std::string json) { e.size = game.getInt("size"); e.downloadURL = game.getString("download-url", ""); e.iconURL = game.getString("icon-url", ""); - e.hidden = game.getBool("hidden", false); + e.hidden = false; // NOTE: Handling of the "hidden" flag is broken in old versions of PPSSPP. Do not use. const char *file = game.getString("file", nullptr); if (!file) continue; @@ -458,11 +445,12 @@ void StoreScreen::CreateViews() { auto di = GetI18NCategory("Dialog"); auto st = GetI18NCategory("Store"); + auto mm = GetI18NCategory("MainMenu"); // Top bar LinearLayout *topBar = root_->Add(new LinearLayout(ORIENT_HORIZONTAL)); topBar->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); - titleText_ = new TextView("PPSSPP Homebrew Store"); + titleText_ = new TextView(mm->T("PPSSPP Homebrew Store")); topBar->Add(titleText_); UI::Drawable solid(0xFFbd9939); topBar->SetBG(solid); @@ -471,7 +459,10 @@ void StoreScreen::CreateViews() { if (connectionError_ || loading_) { content = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)); content->Add(new TextView(loading_ ? std::string(st->T("Loading...")) : StringFromFormat("%s: %d", st->T("Connection Error"), resultCode_))); - content->Add(new Button(di->T("Retry")))->OnClick.Handle(this, &StoreScreen::OnRetry); + if (!loading_) { + content->Add(new Button(di->T("Retry")))->OnClick.Handle(this, &StoreScreen::OnRetry); + + } content->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); scrollItemView_ = nullptr; @@ -484,8 +475,7 @@ void StoreScreen::CreateViews() { scrollItemView_ = new LinearLayoutList(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); leftScroll->Add(scrollItemView_); - std::vector entries = FilterEntries(); - for (size_t i = 0; i < entries.size(); i++) { + for (size_t i = 0; i < entries_.size(); i++) { scrollItemView_->Add(new ProductItemView(entries_[i]))->OnClick.Handle(this, &StoreScreen::OnGameSelected); } @@ -511,9 +501,7 @@ void StoreScreen::CreateViews() { std::vector StoreScreen::FilterEntries() { std::vector filtered; for (size_t i = 0; i < entries_.size(); i++) { - // TODO: Actually filter by category etc. - if (!entries_[i].hidden) - filtered.push_back(entries_[i]); + filtered.push_back(entries_[i]); } return filtered; } diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index b52b09f7a8..164fc86f3a 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -22,6 +22,7 @@ #include "Common/Render/DrawBuffer.h" #include "Common/Data/Text/I18n.h" #include "Common/Math/math_util.h" +#include "Common/System/Display.h" #include "Common/UI/Context.h" #include "Common/CommonTypes.h" @@ -54,9 +55,7 @@ public: void Draw(UIContext &dc) override { scale_ = theScale_*layoutAreaScale; // Scale down just for rendering - dc.PushScissor(screenBounds_); MultiTouchButton::Draw(dc); - dc.PopScissor(); scale_ = theScale_/layoutAreaScale; // is this is needed? } @@ -117,7 +116,6 @@ public: void Draw(UIContext &dc) override { scale_ = theScale_*layoutAreaScale; - dc.PushScissor(screenBounds_); uint32_t colorBg = colorAlpha(GetButtonColor(), GetButtonOpacity()); uint32_t color = colorAlpha(0xFFFFFF, GetButtonOpacity()); @@ -146,7 +144,6 @@ public: dc.Draw()->DrawImageRotated(roundId_, centerX - spacing, centerY, scale_, 0, colorBg, false); dc.Draw()->DrawImageRotated(squareId_, centerX - spacing, centerY, scale_, 0, color, false); } - dc.PopScissor(); scale_ = theScale_/layoutAreaScale; }; @@ -247,7 +244,6 @@ public: void Draw(UIContext &dc) override { scale_ = theScale_*layoutAreaScale; - dc.PushScissor(screenBounds_); uint32_t colorBg = colorAlpha(GetButtonColor(), GetButtonOpacity()); uint32_t color = colorAlpha(0xFFFFFF, GetButtonOpacity()); @@ -267,7 +263,6 @@ public: dc.Draw()->DrawImageRotated(dirImage, x, y, scale_, angle + PI, colorBg, false); dc.Draw()->DrawImageRotated(ImageID("I_ARROW"), x2, y2, scale_, angle + PI, color); } - dc.PopScissor(); scale_ = theScale_/layoutAreaScale; } @@ -327,10 +322,15 @@ public: dc.BeginNoTex(); float xOffset = bounds_.x; float yOffset = bounds_.y; - for (int x = x1; x < x2; x += g_Config.iTouchSnapGridSize) + + dc.Draw()->Rect((x1+x2)/2 + xOffset - pixel_in_dps_x, y1 + yOffset, 3.0*pixel_in_dps_x, y2-y1, col); + dc.Draw()->Rect(x1 + xOffset, (y1+y2)/2 + yOffset - pixel_in_dps_y, x2-x1, 3.0*pixel_in_dps_y, col); + + for (int x = x1 + (x1+x2)/2 % g_Config.iTouchSnapGridSize; x < x2; x += g_Config.iTouchSnapGridSize) dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col); - for (int y = y1; y < y2; y += g_Config.iTouchSnapGridSize) + for (int y = y1 + (y1+y2)/2 % g_Config.iTouchSnapGridSize; y < y2; y += g_Config.iTouchSnapGridSize) dc.Draw()->hLine(x1 + xOffset, y + yOffset, x2 + xOffset, col); + dc.Flush(); dc.Begin(); } @@ -351,10 +351,12 @@ class ControlLayoutView : public UI::AnchorLayout { public: explicit ControlLayoutView(UI::LayoutParams *layoutParams) : UI::AnchorLayout(layoutParams) { + SetClip(true); } - void Touch(const TouchInput &input) override; + bool Touch(const TouchInput &input) override; void CreateViews(); + void Draw(UIContext& ui) override; bool HasCreatedViews() const { return !controls_.empty(); } @@ -378,7 +380,7 @@ static Point ClampTo(const Point &p, const Bounds &b) { return Point(clamp_value(p.x, b.x, b.x + b.w), clamp_value(p.y, b.y, b.y + b.h)); } -void ControlLayoutView::Touch(const TouchInput &touch) { +bool ControlLayoutView::Touch(const TouchInput &touch) { using namespace UI; if ((touch.flags & TOUCH_MOVE) && pickedControl_ != nullptr) { @@ -401,8 +403,8 @@ void ControlLayoutView::Touch(const TouchInput &touch) { newPos.x = startObjectX_ + (touch.x - startDragX_); newPos.y = startObjectY_ + (touch.y - startDragY_); if (g_Config.bTouchSnapToGrid) { - newPos.x -= fmod(newPos.x - controlBounds.w, g_Config.iTouchSnapGridSize); - newPos.y -= fmod(newPos.y - controlBounds.h, g_Config.iTouchSnapGridSize); + newPos.x -= fmod(newPos.x - validRange.w/2, g_Config.iTouchSnapGridSize); + newPos.y -= fmod(newPos.y - validRange.h/2, g_Config.iTouchSnapGridSize); } newPos = ClampTo(newPos, validRange); @@ -446,6 +448,14 @@ void ControlLayoutView::Touch(const TouchInput &touch) { pickedControl_->SavePosition(); pickedControl_ = 0; } + return true; +} + +void ControlLayoutView::Draw(UIContext& dc) { + using namespace UI; + dc.FillRect(Drawable(0x80000000), bounds_); + dc.Flush(); + UI::AnchorLayout::Draw(dc); } void ControlLayoutView::CreateViews() { @@ -557,8 +567,6 @@ DragDropButton *ControlLayoutView::getPickedControl(const int x, const int y) { return bestMatch; } -TouchControlLayoutScreen::TouchControlLayoutScreen() {} - void TouchControlLayoutScreen::resized() { RecreateViews(); } @@ -568,7 +576,7 @@ void TouchControlLayoutScreen::onFinish(DialogResult reason) { } UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) { - screenManager()->push(new TouchControlVisibilityScreen()); + screenManager()->push(new TouchControlVisibilityScreen(gamePath_)); return UI::EVENT_DONE; } @@ -612,16 +620,19 @@ void TouchControlLayoutScreen::CreateViews() { const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); InitPadLayout(bounds.w, bounds.h); - const float leftColumnWidth = 170.0f; - layoutAreaScale = 1.0-(leftColumnWidth+10)/bounds.w; + const float leftColumnWidth = 200.0f; + layoutAreaScale = 1.0f - (leftColumnWidth + 10.0f) / std::max(bounds.w, 1.0f); auto co = GetI18NCategory("Controls"); auto di = GetI18NCategory("Dialog"); - root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + auto rootLayout = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); + rootLayout->SetSpacing(0.0f); + root_ = rootLayout; - ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10))); - LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); + ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(leftColumnWidth, FILL_PARENT))); + leftColumnScroll->SetAlignOpposite(true); + LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(Margins(12.0f, 0.0f)))); mode_ = new ChoiceStrip(ORIENT_VERTICAL); mode_->AddChoice(di->T("Move")); @@ -630,7 +641,7 @@ void TouchControlLayoutScreen::CreateViews() { mode_->OnChoice.Handle(this, &TouchControlLayoutScreen::OnMode); CheckBox *snap = new CheckBox(&g_Config.bTouchSnapToGrid, di->T("Snap")); - PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158)); + PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), ""); gridSize->SetEnabledPtr(&g_Config.bTouchSnapToGrid); leftColumn->Add(mode_); @@ -638,9 +649,12 @@ void TouchControlLayoutScreen::CreateViews() { leftColumn->Add(snap); leftColumn->Add(gridSize); leftColumn->Add(new Choice(di->T("Reset")))->OnClick.Handle(this, &TouchControlLayoutScreen::OnReset); - leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); + leftColumn->Add(new Spacer(12.0f)); + leftColumn->Add(new Choice(di->T("Back"), "", false))->OnClick.Handle(this, &UIScreen::OnBack); + leftColumn->Add(new Spacer(0.0f)); - root_->Add(new BorderView(BORDER_BOTTOM, BorderStyle::ITEM_DOWN_BG, 4.0f, new AnchorLayoutParams(leftColumnWidth + 10, bounds.h * (1.0f - layoutAreaScale), 0.0f, NONE, false))); - root_->Add(new BorderView(BORDER_RIGHT, BorderStyle::ITEM_DOWN_BG, 4.0f, new AnchorLayoutParams(leftColumnWidth + 10, 0.0f, NONE, 0.0f, false))); - layoutView_ = root_->Add(new ControlLayoutView(new AnchorLayoutParams(leftColumnWidth + 10, bounds.h * (1.0 - layoutAreaScale), 0.0f, 0.0f, false))); + LinearLayout* rightColumn = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f, Margins(0.0f, 12.0f, 12.0f, 12.0f)))); + rightColumn->Add(new Spacer(new LinearLayoutParams(1.0))); + float previewHeight = bounds.h * layoutAreaScale; + layoutView_ = rightColumn->Add(new ControlLayoutView(new LinearLayoutParams(FILL_PARENT, previewHeight))); } diff --git a/UI/TouchControlLayoutScreen.h b/UI/TouchControlLayoutScreen.h index 9834f217f0..43c5762f4f 100644 --- a/UI/TouchControlLayoutScreen.h +++ b/UI/TouchControlLayoutScreen.h @@ -23,22 +23,22 @@ class ControlLayoutView; -class TouchControlLayoutScreen : public UIDialogScreenWithBackground { +class TouchControlLayoutScreen : public UIDialogScreenWithGameBackground { public: - TouchControlLayoutScreen(); + TouchControlLayoutScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} - virtual void CreateViews() override; - virtual void dialogFinished(const Screen *dialog, DialogResult result) override; - virtual void onFinish(DialogResult reason) override; - virtual void update() override; - virtual void resized() override; + void CreateViews() override; + void dialogFinished(const Screen *dialog, DialogResult result) override; + void onFinish(DialogResult reason) override; + void update() override; + void resized() override; const char *tag() const override { return "TouchControlLayout"; } protected: - virtual UI::EventReturn OnReset(UI::EventParams &e); - virtual UI::EventReturn OnVisibility(UI::EventParams &e); - virtual UI::EventReturn OnMode(UI::EventParams &e); + UI::EventReturn OnReset(UI::EventParams &e); + UI::EventReturn OnVisibility(UI::EventParams &e); + UI::EventReturn OnMode(UI::EventParams &e); private: UI::ChoiceStrip *mode_ = nullptr; diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index a9110810ee..8bfb3c90d5 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -84,48 +84,48 @@ void TouchControlVisibilityScreen::CreateViews() { toggles_.push_back({ "Dpad", &g_Config.touchDpad.show, ImageID::invalid(), nullptr }); toggles_.push_back({ "Analog Stick", &g_Config.touchAnalogStick.show, ImageID::invalid(), nullptr }); toggles_.push_back({ "Right Analog Stick", &g_Config.touchRightAnalogStick.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new RightAnalogMappingScreen()); + screenManager()->push(new RightAnalogMappingScreen(gamePath_)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Fast-forward", &g_Config.touchFastForwardKey.show, ImageID::invalid(), nullptr }); toggles_.push_back({ "Custom 1", &g_Config.touchCombo0.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(0)); + screenManager()->push(new ComboKeyScreen(gamePath_, 0)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 2", &g_Config.touchCombo1.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(1)); + screenManager()->push(new ComboKeyScreen(gamePath_, 1)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 3", &g_Config.touchCombo2.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(2)); + screenManager()->push(new ComboKeyScreen(gamePath_, 2)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 4", &g_Config.touchCombo3.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(3)); + screenManager()->push(new ComboKeyScreen(gamePath_, 3)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 5", &g_Config.touchCombo4.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(4)); + screenManager()->push(new ComboKeyScreen(gamePath_, 4)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 6", &g_Config.touchCombo5.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(5)); + screenManager()->push(new ComboKeyScreen(gamePath_, 5)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 7", &g_Config.touchCombo6.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(6)); + screenManager()->push(new ComboKeyScreen(gamePath_, 6)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 8", &g_Config.touchCombo7.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(7)); + screenManager()->push(new ComboKeyScreen(gamePath_, 7)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 9", &g_Config.touchCombo8.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(8)); + screenManager()->push(new ComboKeyScreen(gamePath_, 8)); return UI::EVENT_DONE; }}); toggles_.push_back({ "Custom 10", &g_Config.touchCombo9.show, ImageID::invalid(), [=](EventParams &e) { - screenManager()->push(new ComboKeyScreen(9)); + screenManager()->push(new ComboKeyScreen(gamePath_, 9)); return UI::EVENT_DONE; }}); diff --git a/UI/TouchControlVisibilityScreen.h b/UI/TouchControlVisibilityScreen.h index 52d6d00eea..c21efbde8f 100644 --- a/UI/TouchControlVisibilityScreen.h +++ b/UI/TouchControlVisibilityScreen.h @@ -31,8 +31,9 @@ struct TouchButtonToggle { std::function handle; }; -class TouchControlVisibilityScreen : public UIDialogScreenWithBackground { +class TouchControlVisibilityScreen : public UIDialogScreenWithGameBackground { public: + TouchControlVisibilityScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} void CreateViews() override; void onFinish(DialogResult result) override; @@ -46,8 +47,9 @@ private: bool nextToggleAll_ = true; }; -class RightAnalogMappingScreen : public UIDialogScreenWithBackground { +class RightAnalogMappingScreen : public UIDialogScreenWithGameBackground { public: + RightAnalogMappingScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {} void CreateViews() override; const char *tag() const override { return "RightAnalogMapping"; } diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 666e35aa02..df884f757b 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -42,7 +42,6 @@ - @@ -61,7 +60,6 @@ - @@ -76,7 +74,6 @@ - @@ -96,7 +93,6 @@ - diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 2c63641535..3743fe242f 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -63,11 +63,9 @@ Screens - Screens - Screens @@ -81,6 +79,7 @@ Screens + @@ -144,12 +143,10 @@ Screens - Screens - Screens @@ -163,6 +160,7 @@ Screens + diff --git a/UWP/App.cpp b/UWP/App.cpp index aa850ae81a..13611a04f2 100644 --- a/UWP/App.cpp +++ b/UWP/App.cpp @@ -57,20 +57,20 @@ void App::Initialize(CoreApplicationView^ applicationView) { CoreApplication::Resuming += ref new EventHandler(this, &App::OnResuming); - // At this point we have access to the device. + // At this point we have access to the device. // We can create the device-dependent resources. m_deviceResources = std::make_shared(); } // Called when the CoreWindow object is created (or re-created). void App::SetWindow(CoreWindow^ window) { - window->SizeChanged += + window->SizeChanged += ref new TypedEventHandler(this, &App::OnWindowSizeChanged); window->VisibilityChanged += ref new TypedEventHandler(this, &App::OnVisibilityChanged); - window->Closed += + window->Closed += ref new TypedEventHandler(this, &App::OnWindowClosed); DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView(); @@ -267,7 +267,7 @@ void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ ar PSP_CoreParameter().pixelWidth = (int)(width * scale); PSP_CoreParameter().pixelHeight = (int)(height * scale); if (UpdateScreenScale((int)width, (int)height)) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); } } diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj b/UWP/Armips_UWP/Armips_UWP.vcxproj index a836263550..4610681d23 100644 --- a/UWP/Armips_UWP/Armips_UWP.vcxproj +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj @@ -278,6 +278,12 @@ + + + + + + @@ -329,6 +335,12 @@ + + + + + + diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj.filters b/UWP/Armips_UWP/Armips_UWP.vcxproj.filters index 37d23a6b09..0ba78a266d 100644 --- a/UWP/Armips_UWP/Armips_UWP.vcxproj.filters +++ b/UWP/Armips_UWP/Armips_UWP.vcxproj.filters @@ -56,6 +56,24 @@ Archs\MIPS + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + Archs @@ -202,6 +220,24 @@ Archs\MIPS + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + Archs @@ -300,6 +336,9 @@ {bef7b4a2-b049-4d00-810c-6d8d6605c2a3} + + {bef7b4a2-b049-4d00-810c-6d8d6605c2a4} + {2ce1016b-f93c-48b9-abe5-d3fbbcd24780} diff --git a/UWP/Common/DeviceResources.cpp b/UWP/Common/DeviceResources.cpp index 8527d77f51..ab1bbcbf40 100644 --- a/UWP/Common/DeviceResources.cpp +++ b/UWP/Common/DeviceResources.cpp @@ -470,13 +470,13 @@ void DX::DeviceResources::SetWindow(CoreWindow^ window) try { const auto dm = hdi->GetCurrentDisplayMode(); - const unsigned int hdmi_width = dm->ResolutionWidthInRawPixels; - const unsigned int hdmi_height = dm->ResolutionHeightInRawPixels; + const float hdmi_width = (float)dm->ResolutionWidthInRawPixels; + const float hdmi_height = (float)dm->ResolutionHeightInRawPixels; // If we're running on Xbox, use the HDMI mode instead of the CoreWindow size. // In UWP, the CoreWindow is always 1920x1080, even when running at 4K. m_logicalSize = Windows::Foundation::Size(hdmi_width, hdmi_height); - m_dpi = currentDisplayInformation->LogicalDpi * 1.5; + m_dpi = currentDisplayInformation->LogicalDpi * 1.5f; } catch (const Platform::Exception^) { diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index 09e9173e41..930306c7f7 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -203,7 +203,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotUsing @@ -217,7 +217,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -232,7 +232,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -248,7 +248,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) NotUsing @@ -263,7 +263,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) NotUsing @@ -277,7 +277,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -292,7 +292,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -307,7 +307,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -322,7 +322,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) pch.h NotUsing @@ -338,7 +338,7 @@ false false pch.h - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotUsing @@ -352,7 +352,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -367,7 +367,7 @@ false false - ../..;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../..;../../ext/openxr;../../ext/native;../../ext/snappy;../../ext/glslang;../../ext/zlib;../../ext/libpng17;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) NOMINMAX;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) pch.h NotUsing @@ -387,6 +387,7 @@ + @@ -447,6 +448,7 @@ + @@ -494,6 +496,7 @@ + @@ -502,6 +505,13 @@ + + + + + + + @@ -520,6 +530,7 @@ + @@ -569,6 +580,7 @@ + @@ -604,6 +616,7 @@ + @@ -612,6 +625,13 @@ + + + + + + + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 23de400ce6..954e21c236 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -85,6 +85,12 @@ {28139b08-f8d5-41a2-a5ee-bf86cf1469c3} + + {a5bfc343-9c3a-43ff-a033-7b0406e13816} + + + {096c3d00-fcfa-4877-8cf0-3b10d56b5d72} + @@ -375,6 +381,36 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + GPU\Vulkan + + + UI + + + Render + @@ -694,6 +730,36 @@ Math + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + VR + + + GPU\Vulkan + + + UI + + + Render + diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index e4ed18b8f2..b734f6e3d2 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -406,10 +406,6 @@ float System_GetPropertyFloat(SystemProperty prop) { } } -bool VulkanMayBeAvailable() { - return false; -} - void System_Toast(const char *str) {} bool System_GetPropertyBool(SystemProperty prop) { diff --git a/UWP/Package.appxmanifest b/UWP/Package.appxmanifest index dc955c64bb..68b9c930d7 100644 --- a/UWP/Package.appxmanifest +++ b/UWP/Package.appxmanifest @@ -1,9 +1,11 @@  - - + + + - DUMMY - DUMMY + PPSSPP - PSP emulator + Henrik Rydgård + Assets\StoreLogo.png @@ -11,4 +13,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index c6534b2cd9..e2698447e0 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -386,7 +386,6 @@ - @@ -407,7 +406,6 @@ - @@ -423,7 +421,6 @@ - @@ -444,7 +441,6 @@ - @@ -467,4 +463,4 @@ - + \ No newline at end of file diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index bae3799bc9..e26481b823 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -8,7 +8,6 @@ - @@ -28,11 +27,12 @@ - + + @@ -43,7 +43,6 @@ - @@ -63,10 +62,11 @@ - + + - + \ No newline at end of file diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 3b7f8013d4..5fcdbecf25 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -1597,34 +1597,6 @@ true true - - true - true - true - true - true - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - true - true - true - true - true true @@ -1774,4 +1746,4 @@ - \ No newline at end of file + diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters index 03611fcc46..15c471b062 100644 --- a/UWP/UWP.vcxproj.filters +++ b/UWP/UWP.vcxproj.filters @@ -273,12 +273,6 @@ Content\shaders - - Content\shaders - - - Content\shaders - Content\flash0\font @@ -377,4 +371,4 @@ Content - \ No newline at end of file + diff --git a/Windows/CaptureDevice.cpp b/Windows/CaptureDevice.cpp index e522c7b24e..7b61fa6fa0 100644 --- a/Windows/CaptureDevice.cpp +++ b/Windows/CaptureDevice.cpp @@ -716,7 +716,7 @@ std::vector WindowsCaptureDevice::getDeviceList(bool forceEnum, int // Get the size needed first dwMinSize = WideCharToMultiByte(CP_UTF8, NULL, pwstrName, -1, nullptr, 0, nullptr, FALSE); if (dwMinSize == 0) - hr = -1; + hr = E_FAIL; } if (SUCCEEDED(hr)) { cstrName = new char[dwMinSize]; diff --git a/Windows/CaptureDevice.h b/Windows/CaptureDevice.h index d457702afe..d0ed3b4b5f 100644 --- a/Windows/CaptureDevice.h +++ b/Windows/CaptureDevice.h @@ -116,12 +116,12 @@ class WindowsCaptureDevice; class ReaderCallback final : public IMFSourceReaderCallback { public: ReaderCallback(WindowsCaptureDevice *device); - ~ReaderCallback(); + virtual ~ReaderCallback(); // IUnknown methods. - STDMETHODIMP QueryInterface(REFIID iid, void** ppv); - STDMETHODIMP_(ULONG) AddRef() { return 0; } // Unused, just define. - STDMETHODIMP_(ULONG) Release() { return 0; } // Unused, just define. + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override; + STDMETHODIMP_(ULONG) AddRef() override { return 0; } // Unused, just define. + STDMETHODIMP_(ULONG) Release() override { return 0; } // Unused, just define. // IMFSourceReaderCallback methods. STDMETHODIMP OnReadSample( @@ -130,10 +130,10 @@ public: DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample // Can be null,even if hrStatus is success. - ); + ) override; - STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) { return S_OK; } - STDMETHODIMP OnFlush(DWORD) { return S_OK; } + STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) override { return S_OK; } + STDMETHODIMP OnFlush(DWORD) override { return S_OK; } AVPixelFormat getAVVideoFormatbyMFVideoFormat(const GUID &MFVideoFormat); AVSampleFormat getAVAudioFormatbyMFAudioFormat(const GUID &MFAudioFormat, const u32 &bitsPerSample); diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index 96265d5eac..9144a3be4f 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -183,6 +183,8 @@ bool DSoundAudioBackend::Init(HWND window, StreamCallback _callback, int sampleR sampleRate_ = sampleRate; threadData_ = 0; hThread_ = (HANDLE)_beginthreadex(0, 0, soundThread, (void *)this, 0, 0); + if (!hThread_) + return false; SetThreadPriority(hThread_, THREAD_PRIORITY_ABOVE_NORMAL); return true; } diff --git a/Windows/DSoundStream.h b/Windows/DSoundStream.h index 7b4798449a..b3ebe194ab 100644 --- a/Windows/DSoundStream.h +++ b/Windows/DSoundStream.h @@ -11,7 +11,7 @@ struct IDirectSoundBuffer; class DSoundAudioBackend : public WindowsAudioBackend { public: DSoundAudioBackend(); - ~DSoundAudioBackend() override; + ~DSoundAudioBackend(); bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object void Update() override; diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 7faf3b6f2b..a179749ecf 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -332,8 +332,7 @@ void CtrlDisAsmView::assembleOpcode(u32 address, std::string defaultText) } -void CtrlDisAsmView::drawBranchLine(HDC hdc, std::map& addressPositions, BranchLine& line) -{ +void CtrlDisAsmView::drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line) { HPEN pen; u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows); diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h index 9d58de1935..2930e41544 100644 --- a/Windows/Debugger/CtrlDisAsmView.h +++ b/Windows/Debugger/CtrlDisAsmView.h @@ -72,7 +72,7 @@ class CtrlDisAsmView void calculatePixelPositions(); bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData); void updateStatusBarText(); - void drawBranchLine(HDC hdc, std::map& addressPositions, BranchLine& line); + void drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line); void copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm); std::set getSelectedLineArguments(); void drawArguments(HDC hdc, const DisassemblyLineInfo &line, int x, int y, int textColor, const std::set ¤tArguments); diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index c7b98f52c5..00a7b1ed51 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -901,8 +901,8 @@ void CDisasm::ProcessUpdateDialog() { // Update Debug Counter if (PSP_IsInited()) { - wchar_t tempTicks[24]; - _snwprintf(tempTicks, 24, L"%lld", CoreTiming::GetTicks() - lastTicks); + wchar_t tempTicks[24]{}; + _snwprintf(tempTicks, 23, L"%lld", CoreTiming::GetTicks() - lastTicks); SetDlgItemText(m_hDlg, IDC_DEBUG_COUNT, tempTicks); } diff --git a/Windows/Debugger/Debugger_Lists.h b/Windows/Debugger/Debugger_Lists.h index 43dd834a44..b553de5f7b 100644 --- a/Windows/Debugger/Debugger_Lists.h +++ b/Windows/Debugger/Debugger_Lists.h @@ -15,11 +15,11 @@ public: void showMenu(int itemIndex, const POINT &pt); const char* getCurrentThreadName(); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int) threads.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); - virtual void OnRightClick(int itemIndex, int column, const POINT& point); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int) threads.size(); } + void OnDoubleClick(int itemIndex, int column) override; + void OnRightClick(int itemIndex, int column, const POINT &point) override; private: std::vector threads; }; @@ -31,14 +31,13 @@ class CtrlBreakpointList: public GenericListControl public: CtrlBreakpointList(HWND hwnd, DebugInterface* cpu, CtrlDisAsmView* disasm); void reloadBreakpoints(); - void showMenu(int itemIndex, const POINT &pt); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return getTotalBreakpointCount(); }; - virtual void OnDoubleClick(int itemIndex, int column); - virtual void OnRightClick(int itemIndex, int column, const POINT& point); - virtual void OnToggle(int item, bool newValue); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return getTotalBreakpointCount(); } + void OnDoubleClick(int itemIndex, int column) override; + void OnRightClick(int itemIndex, int column, const POINT &point) override; + void OnToggle(int item, bool newValue) override; private: std::vector displayedBreakPoints_; std::vector displayedMemChecks_; @@ -61,10 +60,10 @@ public: CtrlStackTraceView(HWND hwnd, DebugInterface* cpu, CtrlDisAsmView* disasm); void loadStackTrace(); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int)frames.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int)frames.size(); } + void OnDoubleClick(int itemIndex, int column) override; private: std::vector frames; DebugInterface* cpu; @@ -77,11 +76,11 @@ public: CtrlModuleList(HWND hwnd, DebugInterface* cpu); void loadModules(); protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int)modules.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int)modules.size(); } + void OnDoubleClick(int itemIndex, int column) override; private: std::vector modules; DebugInterface* cpu; -}; \ No newline at end of file +}; diff --git a/Windows/Debugger/Debugger_MemoryDlg.h b/Windows/Debugger/Debugger_MemoryDlg.h index b02d72d0d9..4e47d37be1 100644 --- a/Windows/Debugger/Debugger_MemoryDlg.h +++ b/Windows/Debugger/Debugger_MemoryDlg.h @@ -19,7 +19,7 @@ private: HWND memViewHdl, symListHdl, editWnd, searchBoxHdl, srcListHdl; HWND layerDropdown_; HWND status_; - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; public: int index; //helper @@ -33,11 +33,9 @@ public: ~CMemoryDlg(void); void Goto(u32 addr); - void Update(void); + void Update(void) override; void NotifyMapLoaded(); - void NotifySearchCompleted(); - void Size(void); private: diff --git a/Windows/Debugger/Debugger_VFPUDlg.h b/Windows/Debugger/Debugger_VFPUDlg.h index 0e5763dcfc..080957a7a9 100644 --- a/Windows/Debugger/Debugger_VFPUDlg.h +++ b/Windows/Debugger/Debugger_VFPUDlg.h @@ -10,7 +10,7 @@ public: ~CVFPUDlg(); void Goto(u32 addr); - void Update(); + void Update() override; void Size(); private: @@ -18,5 +18,5 @@ private: DebugInterface *cpu; HFONT font; int mode; - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; }; diff --git a/Windows/Debugger/DumpMemoryWindow.cpp b/Windows/Debugger/DumpMemoryWindow.cpp index 1f852611c2..884ba3bccf 100644 --- a/Windows/Debugger/DumpMemoryWindow.cpp +++ b/Windows/Debugger/DumpMemoryWindow.cpp @@ -229,8 +229,8 @@ void DumpMemoryWindow::changeMode(HWND hwnd, Mode newMode) if (filenameChosen_ == false) SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),"Custom.dump"); } else { - u32 start, size; - const char* defaultFileName; + u32 start = 0, size = 0; + const char *defaultFileName = ""; switch (selectedMode) { diff --git a/Windows/DinputDevice.h b/Windows/DinputDevice.h index d8ecc8762f..5dc2474e2a 100644 --- a/Windows/DinputDevice.h +++ b/Windows/DinputDevice.h @@ -32,7 +32,7 @@ public: //getDevices(), enumerates all devices if not done yet DinputDevice(int devnum); ~DinputDevice(); - virtual int UpdateState() override; + int UpdateState() override; static size_t getNumPads(); static void CheckDevices() { needsCheck_ = true; diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index 24e7ffd280..56f1d24746 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -81,7 +81,7 @@ public: StepCountDlg(HINSTANCE _hInstance, HWND _hParent); ~StepCountDlg(); protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void Jump(int count, bool relative); }; @@ -94,7 +94,7 @@ public: static void Init(); protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void SetupPreviews(); diff --git a/Windows/GEDebugger/TabDisplayLists.h b/Windows/GEDebugger/TabDisplayLists.h index ff4388225a..5e31a49341 100644 --- a/Windows/GEDebugger/TabDisplayLists.h +++ b/Windows/GEDebugger/TabDisplayLists.h @@ -12,12 +12,15 @@ class CtrlDisplayListStack: public GenericListControl { public: CtrlDisplayListStack(HWND hwnd); - void setDisplayList(DisplayList& _list) { list = _list; Update(); } + void setDisplayList(const DisplayList &_list) { + list = _list; + Update(); + } protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) { return false; }; - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return list.stackptr; }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override { return false; } + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return list.stackptr; } + void OnDoubleClick(int itemIndex, int column) override; private: DisplayList list; }; @@ -26,12 +29,15 @@ class CtrlAllDisplayLists: public GenericListControl { public: CtrlAllDisplayLists(HWND hwnd); - void setDisplayLists(std::vector& _lists) { lists = _lists; Update(); }; + void setDisplayLists(const std::vector &_lists) { + lists = _lists; + Update(); + } protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); - virtual void GetColumnText(wchar_t* dest, int row, int col); - virtual int GetRowCount() { return (int) lists.size(); }; - virtual void OnDoubleClick(int itemIndex, int column); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int) lists.size(); } + void OnDoubleClick(int itemIndex, int column) override; private: std::vector lists; }; @@ -43,7 +49,7 @@ public: ~TabDisplayLists(); void Update(bool reload = true); protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void UpdateSize(WORD width, WORD height); diff --git a/Windows/GEDebugger/TabState.h b/Windows/GEDebugger/TabState.h index 6992af14be..f525b02723 100644 --- a/Windows/GEDebugger/TabState.h +++ b/Windows/GEDebugger/TabState.h @@ -63,7 +63,7 @@ public: } protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; CtrlStateValues *values; diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index f7ab9af7ac..35ab37e498 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -293,7 +293,7 @@ int CtrlVertexList::GetRowCount() { DisplayList list; if (gpuDebug->GetCurrentDisplayList(list)) { u32 cmd = Memory::Read_U32(list.pc); - if ((cmd >> 24) == GE_CMD_PRIM) { + if ((cmd >> 24) == GE_CMD_PRIM || (cmd >> 24) == GE_CMD_BOUNDINGBOX) { rowCount_ = cmd & 0xFFFF; } else if ((cmd >> 24) == GE_CMD_BEZIER || (cmd >> 24) == GE_CMD_SPLINE) { u32 u = (cmd & 0x00FF) >> 0; @@ -306,6 +306,8 @@ int CtrlVertexList::GetRowCount() { rowCount_ = 0; } VertexDecoderOptions options{}; + // TODO: Maybe an option? + options.applySkinInDecode = true; decoder->SetVertexType(state.vertType, options); return rowCount_; } diff --git a/Windows/GEDebugger/TabVertices.h b/Windows/GEDebugger/TabVertices.h index 0a1f48be0c..4d7a04d660 100644 --- a/Windows/GEDebugger/TabVertices.h +++ b/Windows/GEDebugger/TabVertices.h @@ -35,9 +35,9 @@ public: } protected: - virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) { return false; }; - virtual void GetColumnText(wchar_t *dest, int row, int col); - virtual int GetRowCount(); + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override { return false; } + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override; private: void FormatVertCol(wchar_t *dest, const GPUDebugVertex &vert, int col); @@ -57,12 +57,12 @@ public: TabVertices(HINSTANCE _hInstance, HWND _hParent); ~TabVertices(); - virtual void Update() { + void Update() override { values->Update(); } protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void UpdateSize(WORD width, WORD height); @@ -98,12 +98,12 @@ public: TabMatrices(HINSTANCE _hInstance, HWND _hParent); ~TabMatrices(); - virtual void Update() { + void Update() override { values->Update(); } protected: - BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; private: void UpdateSize(WORD width, WORD height); diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index e919a10420..05afc4d1f5 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -90,7 +90,7 @@ void WindowsGLContext::Resume() { void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenum type, GLuint id, GLenum severity, const char *msg) { - char sourceStr[32]; + char sourceStr[32]{}; const char *sourceFmt; switch(source) { case GL_DEBUG_SOURCE_API_ARB: sourceFmt = "API"; break; @@ -103,7 +103,7 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu } snprintf(sourceStr, sizeof(sourceStr), sourceFmt, source); - char typeStr[32]; + char typeStr[32]{}; const char *typeFmt; switch(type) { case GL_DEBUG_TYPE_ERROR_ARB: typeFmt = "ERROR"; break; @@ -116,7 +116,7 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu } snprintf(typeStr, sizeof(typeStr), typeFmt, type); - char severityStr[32]; + char severityStr[32]{}; const char *severityFmt; switch (severity) { case GL_DEBUG_SEVERITY_HIGH_ARB: severityFmt = "HIGH"; break; @@ -130,7 +130,7 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu } void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar *message, GLvoid *userParam) { + GLsizei length, const GLchar *message, GLvoid *userParam) { // Ignore buffer mapping messages from NVIDIA if (source == GL_DEBUG_SOURCE_API_ARB && type == GL_DEBUG_TYPE_OTHER_ARB && id == 131185) { return; diff --git a/Windows/GPU/WindowsGLContext.h b/Windows/GPU/WindowsGLContext.h index df8190f9dc..2909be60f1 100644 --- a/Windows/GPU/WindowsGLContext.h +++ b/Windows/GPU/WindowsGLContext.h @@ -47,7 +47,4 @@ private: volatile bool resumeRequested; HANDLE pauseEvent; HANDLE resumeEvent; - - int xres; - int yres; }; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 733e270db3..de6b09baed 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -195,7 +195,7 @@ namespace MainWindow if (g_Config.UseFullScreen() || inFullscreenResize) return; - WINDOWPLACEMENT placement; + WINDOWPLACEMENT placement{}; GetWindowPlacement(hwndMain, &placement); if (placement.showCmd == SW_SHOWNORMAL) { RECT rc; @@ -238,7 +238,7 @@ namespace MainWindow g_Config.iInternalResolution = 0; } - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_renderResized", ""); } void CorrectCursor() { @@ -302,7 +302,8 @@ namespace MainWindow DEBUG_LOG(SYSTEM, "Pixel width/height: %dx%d", PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); if (UpdateScreenScale(width, height)) { - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_displayResized", ""); + NativeMessageReceived("gpu_renderResized", ""); } // Don't save the window state if fullscreen. @@ -967,6 +968,7 @@ namespace MainWindow break; case WM_CLOSE: + MainThread_Stop(); InputDevice::StopPolling(); WindowsRawInput::Shutdown(); return DefWindowProc(hWnd,message,wParam,lParam); @@ -975,8 +977,9 @@ namespace MainWindow KillTimer(hWnd, TIMER_CURSORUPDATE); KillTimer(hWnd, TIMER_CURSORMOVEUPDATE); KillTimer(hWnd, TIMER_WHEELRELEASE); + // Main window is gone, this tells the message loop to exit. PostQuitMessage(0); - break; + return 0; case WM_USER + 1: NotifyDebuggerMapLoaded(); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 384bb9a0f7..25af2cd08e 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -154,68 +154,6 @@ namespace MainWindow { AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_ABOUT, aboutPPSSPP.c_str()); } - void UpdateDynamicMenuCheckmarks(HMENU menu) { - int item = ID_SHADERS_BASE + 1; - - for (size_t i = 0; i < availableShaders.size(); i++) { - bool checked = false; - if (g_Config.vPostShaderNames.empty() && availableShaders[i] == "Off") - checked = true; - else if (g_Config.vPostShaderNames.size() == 1 && availableShaders[i] == g_Config.vPostShaderNames[0]) - checked = true; - - CheckMenuItem(menu, item++, checked ? MF_CHECKED : MF_UNCHECKED); - } - } - - bool CreateShadersSubmenu(HMENU menu) { - // NOTE: We do not load this until translations are loaded! - if (!I18NCategoryLoaded("PostShaders")) - return false; - - // We only reload this initially and when a menu is actually opened. - if (!menuShaderInfoLoaded) { - // This is on Windows where we don't currently blacklist any vendors, or similar. - // TODO: Figure out how to have the GPU data while reloading the post shader info. - ReloadAllPostShaderInfo(nullptr); - menuShaderInfoLoaded = true; - } - - std::vector info = GetAllPostShaderInfo(); - - if (menuShaderInfo.size() == info.size() && std::equal(info.begin(), info.end(), menuShaderInfo.begin())) { - return false; - } - - auto ps = GetI18NCategory("PostShaders"); - - HMENU shaderMenu = GetSubmenuById(menu, ID_OPTIONS_SHADER_MENU); - EmptySubMenu(shaderMenu); - - int item = ID_SHADERS_BASE + 1; - const char *translatedShaderName = nullptr; - - availableShaders.clear(); - for (auto i = info.begin(); i != info.end(); ++i) { - if (!i->visible) - continue; - int checkedStatus = MF_UNCHECKED; - availableShaders.push_back(i->section); - if (g_Config.vPostShaderNames.empty() && i->section == "Off") { - checkedStatus = MF_CHECKED; - } else if (g_Config.vPostShaderNames.size() == 1 && g_Config.vPostShaderNames[0] == i->section) { - checkedStatus = MF_CHECKED; - } - - translatedShaderName = ps->T(i->section.c_str(), i->name.c_str()); - - AppendMenu(shaderMenu, MF_STRING | MF_BYPOSITION | checkedStatus, item++, ConvertUTF8ToWString(translatedShaderName).c_str()); - } - - menuShaderInfo = info; - return true; - } - static void TranslateMenuItem(const HMENU hMenu, const int menuID, const std::wstring& accelerator = L"", const char *key = nullptr) { auto des = GetI18NCategory("DesktopUI"); @@ -302,7 +240,6 @@ namespace MainWindow { // Skip display multipliers x1-x10 TranslateMenuItem(menu, ID_OPTIONS_FULLSCREEN, g_Config.bSystemControls ? L"\tAlt+Return, F11" : L""); TranslateMenuItem(menu, ID_OPTIONS_VSYNC); - TranslateMenuItem(menu, ID_OPTIONS_SHADER_MENU); TranslateMenuItem(menu, ID_OPTIONS_SCREEN_MENU, g_Config.bSystemControls ? L"\tCtrl+1" : L""); TranslateMenuItem(menu, ID_OPTIONS_SCREENAUTO); // Skip rendering resolution 2x-5x.. @@ -315,8 +252,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_OPTIONS_VULKAN); TranslateMenuItem(menu, ID_OPTIONS_RENDERMODE_MENU); - TranslateMenuItem(menu, ID_OPTIONS_NONBUFFEREDRENDERING); - TranslateMenuItem(menu, ID_OPTIONS_BUFFEREDRENDERING); + TranslateMenuItem(menu, ID_OPTIONS_SKIP_BUFFER_EFFECTS); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_MENU, g_Config.bSystemControls ? L"\tF7" : L""); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO); TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0); @@ -361,10 +297,6 @@ namespace MainWindow { changed = true; } - if (CreateShadersSubmenu(menu)) { - changed = true; - } - if (changed) { DrawMenuBar(hWnd); } @@ -473,7 +405,7 @@ namespace MainWindow { // not static void setTexScalingMultiplier(int level) { g_Config.iTexScalingLevel = level; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } static void setTexFiltering(int type) { @@ -486,25 +418,12 @@ namespace MainWindow { static void setTexScalingType(int type) { g_Config.iTexScalingType = type; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); } - static void setRenderingMode(int mode) { - auto gr = GetI18NCategory("Graphics"); - - g_Config.iRenderingMode = mode; - switch (g_Config.iRenderingMode) { - case FB_NON_BUFFERED_MODE: - osm.Show(gr->T("Non-Buffered Rendering")); - g_Config.bAutoFrameSkip = false; - break; - - case FB_BUFFERED_MODE: - osm.Show(gr->T("Buffered Rendering")); - break; - } - - NativeMessageReceived("gpu_resized", ""); + static void setSkipBufferEffects(bool skip) { + g_Config.bSkipBufferEffects = skip; + NativeMessageReceived("gpu_configChanged", ""); } static void setFrameSkipping(int framesToSkip = -1) { @@ -756,9 +675,9 @@ namespace MainWindow { case ID_OPTIONS_FRAMESKIP_AUTO: g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip; - if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - g_Config.iRenderingMode = FB_BUFFERED_MODE; - NativeMessageReceived("gpu_resized", ""); + if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { + g_Config.bSkipBufferEffects = false; + NativeMessageReceived("gpu_configChanged", ""); } break; @@ -775,7 +694,7 @@ namespace MainWindow { case ID_TEXTURESCALING_DEPOSTERIZE: g_Config.bTexDeposterize = !g_Config.bTexDeposterize; - NativeMessageReceived("gpu_clearCache", ""); + NativeMessageReceived("gpu_configChanged", ""); break; case ID_OPTIONS_DIRECT3D9: @@ -802,8 +721,11 @@ namespace MainWindow { RestartApp(); break; - case ID_OPTIONS_NONBUFFEREDRENDERING: setRenderingMode(FB_NON_BUFFERED_MODE); break; - case ID_OPTIONS_BUFFEREDRENDERING: setRenderingMode(FB_BUFFERED_MODE); break; + case ID_OPTIONS_SKIP_BUFFER_EFFECTS: + g_Config.bSkipBufferEffects = !g_Config.bSkipBufferEffects; + NativeMessageReceived("gpu_configChanged", ""); + osm.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects); + break; case ID_DEBUG_SHOWDEBUGSTATISTICS: g_Config.bShowDebugStats = !g_Config.bShowDebugStats; @@ -812,7 +734,7 @@ namespace MainWindow { case ID_OPTIONS_HARDWARETRANSFORM: g_Config.bHardwareTransform = !g_Config.bHardwareTransform; - NativeMessageReceived("gpu_resized", ""); + NativeMessageReceived("gpu_configChanged", ""); osm.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform); break; @@ -1045,25 +967,8 @@ namespace MainWindow { break; default: - { - // Handle the dynamic shader switching here. - // The Menu ID is contained in wParam, so subtract - // ID_SHADERS_BASE and an additional 1 off it. - u32 index = (wParam - ID_SHADERS_BASE - 1); - if (index < availableShaders.size()) { - g_Config.vPostShaderNames.clear(); - if (availableShaders[index] != "Off") - g_Config.vPostShaderNames.push_back(availableShaders[index]); - g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); - - NativeMessageReceived("gpu_resized", ""); - NativeMessageReceived("postshader_updated", ""); - break; - } - MessageBox(hWnd, L"Unimplemented", L"Sorry", 0); - } - break; + break; } } @@ -1095,6 +1000,7 @@ namespace MainWindow { CHECKITEM(ID_FILE_USEFFV1, g_Config.bUseFFV1); CHECKITEM(ID_FILE_DUMP_VIDEO_OUTPUT, g_Config.bDumpVideoOutput); CHECKITEM(ID_FILE_DUMPAUDIO, g_Config.bDumpAudio); + CHECKITEM(ID_OPTIONS_SKIP_BUFFER_EFFECTS, g_Config.bSkipBufferEffects); static const int displayrotationitems[] = { ID_EMULATION_ROTATION_H, @@ -1238,15 +1144,6 @@ namespace MainWindow { CheckMenuItem(menu, bufferfilteritems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iBufFilter ? MF_CHECKED : MF_UNCHECKED)); } - static const int renderingmode[] = { - ID_OPTIONS_NONBUFFEREDRENDERING, - ID_OPTIONS_BUFFEREDRENDERING, - }; - - for (int i = 0; i < ARRAY_SIZE(renderingmode); i++) { - CheckMenuItem(menu, renderingmode[i], MF_BYCOMMAND | ((i == g_Config.iRenderingMode) ? MF_CHECKED : MF_UNCHECKED)); - } - static const int frameskipping[] = { ID_OPTIONS_FRAMESKIP_0, ID_OPTIONS_FRAMESKIP_1, @@ -1348,7 +1245,6 @@ namespace MainWindow { EnableMenuItem(menu, ID_DEBUG_GEDEBUGGER, MF_GRAYED); #endif - UpdateDynamicMenuCheckmarks(menu); UpdateCommands(); } diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 63ecbc1691..67d3f25f66 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -1498,6 +1498,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 0706f8fb9c..9575308dd8 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -711,6 +711,9 @@ Other Platforms\SDL + + Resource Files + diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index c23efbcf88..6a5d779203 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -251,7 +251,7 @@ namespace WindowsRawInput { return windowsTransTable[vKey]; } - void ProcessKeyboard(RAWINPUT *raw, bool foreground) { + void ProcessKeyboard(const RAWINPUT *raw, bool foreground) { if (menuActive && UpdateMenuActive()) { // Ignore keyboard input while a menu is active, it's probably interacting with the menu. return; @@ -302,7 +302,7 @@ namespace WindowsRawInput { return true; } - void ProcessMouse(HWND hWnd, RAWINPUT *raw, bool foreground) { + void ProcessMouse(HWND hWnd, const RAWINPUT *raw, bool foreground) { if (menuActive && UpdateMenuActive()) { // Ignore mouse input while a menu is active, it's probably interacting with the menu. return; @@ -379,15 +379,21 @@ namespace WindowsRawInput { } LRESULT Process(HWND hWnd, WPARAM wParam, LPARAM lParam) { - UINT dwSize; + UINT dwSize = 0; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); if (!rawInputBuffer) { rawInputBuffer = malloc(dwSize); + if (!rawInputBuffer) + return DefWindowProc(hWnd, WM_INPUT, wParam, lParam); memset(rawInputBuffer, 0, dwSize); rawInputBufferSize = dwSize; } if (dwSize > rawInputBufferSize) { - rawInputBuffer = realloc(rawInputBuffer, dwSize); + void *newBuf = realloc(rawInputBuffer, dwSize); + if (!newBuf) + return DefWindowProc(hWnd, WM_INPUT, wParam, lParam); + rawInputBuffer = newBuf; + rawInputBufferSize = dwSize; memset(rawInputBuffer, 0, dwSize); } GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBuffer, &dwSize, sizeof(RAWINPUTHEADER)); diff --git a/Windows/TouchInputHandler.cpp b/Windows/TouchInputHandler.cpp index d27850c759..d0f00e59f6 100644 --- a/Windows/TouchInputHandler.cpp +++ b/Windows/TouchInputHandler.cpp @@ -15,15 +15,12 @@ #include "Windows/MainWindow.h" TouchInputHandler::TouchInputHandler() { - touchInfo = (getTouchInputProc) GetProcAddress( - GetModuleHandle(TEXT("User32.dll")), - "GetTouchInputInfo"); - closeTouch = (closeTouchInputProc) GetProcAddress( - GetModuleHandle(TEXT("User32.dll")), - "CloseTouchInputHandle"); - registerTouch = (registerTouchProc) GetProcAddress( - GetModuleHandle(TEXT("User32.dll")), - "RegisterTouchWindow"); + HMODULE user32 = GetModuleHandle(TEXT("User32.dll")); + if (!user32) + return; + touchInfo = (getTouchInputProc)GetProcAddress(user32, "GetTouchInputInfo"); + closeTouch = (closeTouchInputProc)GetProcAddress(user32, "CloseTouchInputHandle"); + registerTouch = (registerTouchProc)GetProcAddress(user32, "RegisterTouchWindow"); } int TouchInputHandler::ToTouchID(int windowsID, bool allowAllocate) { diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index 4d9d101e41..2d7399f2e2 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -71,12 +71,14 @@ namespace W32Util // Lock the handle and copy the text to the buffer. wchar_t *lptstrCopy = (wchar_t *)GlobalLock(hglbCopy); - wcscpy(lptstrCopy, wtext.c_str()); - lptstrCopy[wtext.size()] = (wchar_t) 0; // null character - GlobalUnlock(hglbCopy); - SetClipboardData(CF_UNICODETEXT, hglbCopy); + if (lptstrCopy) { + wcscpy(lptstrCopy, wtext.c_str()); + lptstrCopy[wtext.size()] = (wchar_t) 0; // null character + GlobalUnlock(hglbCopy); + SetClipboardData(CF_UNICODETEXT, hglbCopy); + } CloseClipboard(); - return TRUE; + return lptstrCopy ? TRUE : FALSE; } void MakeTopMost(HWND hwnd, bool topMost) { diff --git a/Windows/W32Util/ShellUtil.cpp b/Windows/W32Util/ShellUtil.cpp index bd53935d27..2111a24674 100644 --- a/Windows/W32Util/ShellUtil.cpp +++ b/Windows/W32Util/ShellUtil.cpp @@ -33,7 +33,9 @@ namespace W32Util auto idList = SHBrowseForFolder(&info); HMODULE shell32 = GetModuleHandle(L"shell32.dll"); typedef BOOL (WINAPI *SHGetPathFromIDListEx_f)(PCIDLIST_ABSOLUTE pidl, PWSTR pszPath, DWORD cchPath, GPFIDL_FLAGS uOpts); - SHGetPathFromIDListEx_f SHGetPathFromIDListEx_ = (SHGetPathFromIDListEx_f)GetProcAddress(shell32, "SHGetPathFromIDListEx"); + SHGetPathFromIDListEx_f SHGetPathFromIDListEx_ = nullptr; + if (shell32) + SHGetPathFromIDListEx_ = (SHGetPathFromIDListEx_f)GetProcAddress(shell32, "SHGetPathFromIDListEx"); std::string result; if (SHGetPathFromIDListEx_) { @@ -156,7 +158,9 @@ namespace W32Util std::string result; HMODULE shell32 = GetModuleHandle(L"shell32.dll"); typedef HRESULT(WINAPI *SHGetKnownFolderPath_f)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); - SHGetKnownFolderPath_f SHGetKnownFolderPath_ = (SHGetKnownFolderPath_f)GetProcAddress(shell32, "SHGetKnownFolderPath"); + SHGetKnownFolderPath_f SHGetKnownFolderPath_ = nullptr; + if (shell32) + SHGetKnownFolderPath_ = (SHGetKnownFolderPath_f)GetProcAddress(shell32, "SHGetKnownFolderPath"); if (SHGetKnownFolderPath_) { PWSTR path = nullptr; if (SHGetKnownFolderPath_(FOLDERID_Documents, 0, nullptr, &path) == S_OK) { diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index a80155cb0d..53f02245b9 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -38,7 +38,7 @@ public: CMMNotificationClient() { } - ~CMMNotificationClient() { + virtual ~CMMNotificationClient() { CoTaskMemFree(currentDevice_); currentDevice_ = nullptr; SAFE_RELEASE(_pEnumerator) @@ -159,16 +159,13 @@ public: __uuidof(IMMDeviceEnumerator), (void**)&_pEnumerator); } - if (hr == S_OK) - { + if (hr == S_OK && _pEnumerator) { hr = _pEnumerator->GetDevice(pwstrId, &pDevice); } - if (hr == S_OK) - { + if (hr == S_OK && pDevice) { hr = pDevice->OpenPropertyStore(STGM_READ, &pProps); } - if (hr == S_OK) - { + if (hr == S_OK && pProps) { // Get the endpoint device's friendly-name property. hr = pProps->GetValue(PKEY_Device_FriendlyName, &varString); } @@ -224,6 +221,8 @@ bool WASAPIAudioBackend::Init(HWND window, StreamCallback callback, int sampleRa callback_ = callback; sampleRate_ = sampleRate; hThread_ = (HANDLE)_beginthreadex(0, 0, soundThread, (void *)this, 0, 0); + if (!hThread_) + return false; SetThreadPriority(hThread_, THREAD_PRIORITY_ABOVE_NORMAL); return true; } @@ -333,7 +332,7 @@ void WASAPIAudioThread::ShutdownAudioDevice() { } bool WASAPIAudioThread::DetectFormat() { - if (!ValidateFormat(deviceFormat_)) { + if (deviceFormat_ && !ValidateFormat(deviceFormat_)) { // Last chance, let's try to ask for one we support instead. WAVEFORMATEXTENSIBLE fmt{}; fmt.Format.cbSize = sizeof(fmt); @@ -356,7 +355,8 @@ bool WASAPIAudioThread::DetectFormat() { CoTaskMemFree(closest); CoTaskMemFree(deviceFormat_); deviceFormat_ = (WAVEFORMATEXTENSIBLE *)CoTaskMemAlloc(sizeof(fmt)); - memcpy(deviceFormat_, &fmt, sizeof(fmt)); + if (deviceFormat_) + memcpy(deviceFormat_, &fmt, sizeof(fmt)); // In case something above gets out of date. return ValidateFormat(deviceFormat_); @@ -366,13 +366,16 @@ bool WASAPIAudioThread::DetectFormat() { CoTaskMemFree(deviceFormat_); deviceFormat_ = closest; } else { - ERROR_LOG_REPORT_ONCE(badfallbackclosest, SCEAUDIO, "WASAPI fallback and closest unsupported"); + wchar_t guid[256]{}; + StringFromGUID2(closest->SubFormat, guid, 256); + ERROR_LOG_REPORT_ONCE(badfallbackclosest, SCEAUDIO, "WASAPI fallback and closest unsupported (fmt=%04x/%s)", closest->Format.wFormatTag, guid); CoTaskMemFree(closest); return false; } } else { CoTaskMemFree(closest); - ERROR_LOG_REPORT_ONCE(badfallback, SCEAUDIO, "WASAPI fallback format was unsupported"); + if (hr != AUDCLNT_E_DEVICE_INVALIDATED && hr != AUDCLNT_E_SERVICE_NOT_RUNNING) + ERROR_LOG_REPORT_ONCE(badfallback, SCEAUDIO, "WASAPI fallback format was unsupported (%08x)", hr); return false; } } @@ -384,13 +387,17 @@ bool WASAPIAudioThread::ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt) { // Don't know if PCM16 ever shows up here, the documentation only talks about float... but let's blindly // try to support it :P format_ = Format::UNKNOWN; + if (!fmt) + return false; if (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { if (!memcmp(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(fmt->SubFormat))) { if (fmt->Format.nChannels >= 1) format_ = Format::IEEE_FLOAT; } else { - ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format, expected float!"); + wchar_t guid[256]{}; + StringFromGUID2(fmt->SubFormat, guid, 256); + ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format (%S), expected float!", guid); if (fmt->Format.wBitsPerSample == 16 && fmt->Format.nChannels == 2) { format_ = Format::PCM16; } @@ -567,7 +574,8 @@ void WASAPIAudioThread::Run() { } int WASAPIAudioBackend::RunThread() { - CoInitializeEx(nullptr, COINIT_MULTITHREADED); + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + _dbg_assert_(SUCCEEDED(hr)); SetCurrentThreadName("WASAPI_audio"); if (threadData_ == 0) { diff --git a/Windows/WASAPIStream.h b/Windows/WASAPIStream.h index b9e2169a78..9f0b88b40d 100644 --- a/Windows/WASAPIStream.h +++ b/Windows/WASAPIStream.h @@ -8,7 +8,7 @@ class WASAPIAudioBackend : public WindowsAudioBackend { public: WASAPIAudioBackend(); - ~WASAPIAudioBackend() override; + ~WASAPIAudioBackend(); bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object void Update() override {} diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 610b79890b..06e9ef1662 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -269,7 +269,7 @@ void WindowsHost::BootDone() { } static Path SymbolMapFilename(const Path ¤tFilename, const char *ext) { - File::FileInfo info; + File::FileInfo info{}; // can't fail, definitely exists if it gets this far File::GetFileInfo(currentFilename, &info); if (info.isDirectory) { @@ -311,14 +311,16 @@ bool WindowsHost::IsDebuggingEnabled() { // http://msdn.microsoft.com/en-us/library/aa969393.aspx HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) { HRESULT hres; - IShellLink* psl; - CoInitializeEx(NULL, COINIT_MULTITHREADED); + IShellLink *psl = nullptr; + hres = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (FAILED(hres)) + return hres; // Get a pointer to the IShellLink interface. It is assumed that CoInitialize // has already been called. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); - if (SUCCEEDED(hres)) { - IPersistFile* ppf; + if (SUCCEEDED(hres) && psl) { + IPersistFile *ppf = nullptr; // Set the path to the shortcut target and add the description. psl->SetPath(lpszPathObj); @@ -329,7 +331,7 @@ HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathL // shortcut in persistent storage. hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); - if (SUCCEEDED(hres)) { + if (SUCCEEDED(hres) && ppf) { // Save the link by calling IPersistFile::Save. hres = ppf->Save(lpszPathLink, TRUE); ppf->Release(); diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index b9d73c8ecd..3e82015921 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -38,7 +38,7 @@ static XInputGetState_t PPSSPP_XInputGetState = nullptr; static XInputSetState_t PPSSPP_XInputSetState = nullptr; static XInputGetCapabilitiesEx_t PPSSPP_XInputGetCapabilitiesEx = nullptr; static DWORD PPSSPP_XInputVersion = 0; -static HMODULE s_pXInputDLL = 0; +static HMODULE s_pXInputDLL = nullptr; static int s_XInputDLLRefCount = 0; static void UnloadXInputDLL(); @@ -105,7 +105,7 @@ static void UnloadXInputDLL() { if ( s_pXInputDLL ) { if (--s_XInputDLLRefCount == 0) { FreeLibrary( s_pXInputDLL ); - s_pXInputDLL = NULL; + s_pXInputDLL = nullptr; } } } @@ -206,7 +206,7 @@ void XinputDevice::UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATIO if (!notified[pad]) { notified[pad] = true; #if !PPSSPP_PLATFORM(UWP) - XINPUT_CAPABILITIES_EX caps; + XINPUT_CAPABILITIES_EX caps{}; if (PPSSPP_XInputGetCapabilitiesEx != nullptr && PPSSPP_XInputGetCapabilitiesEx(1, pad, 0, &caps) == ERROR_SUCCESS) { KeyMap::NotifyPadConnected(DEVICE_ID_XINPUT_0 + pad, StringFromFormat("Xbox 360 Pad: %d/%d", caps.vendorId, caps.productId)); } else { diff --git a/Windows/XinputDevice.h b/Windows/XinputDevice.h index bcff3e5db8..93347a6722 100644 --- a/Windows/XinputDevice.h +++ b/Windows/XinputDevice.h @@ -8,7 +8,7 @@ class XinputDevice final : public InputDevice { public: XinputDevice(); ~XinputDevice(); - virtual int UpdateState() override; + int UpdateState() override; private: void UpdatePad(int pad, const XINPUT_STATE &state, XINPUT_VIBRATION &vibration); diff --git a/Windows/main.cpp b/Windows/main.cpp index 6584f0cf65..9351202bee 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -113,7 +113,7 @@ void OpenDirectory(const char *path) { // SHParseDisplayName can't handle relative paths, so normalize first. std::string resolved = ReplaceAll(File::ResolvePath(path), "/", "\\"); - SFGAOF flags; + SFGAOF flags{}; PIDLIST_ABSOLUTE pidl = nullptr; HRESULT hr = SHParseDisplayName(ConvertUTF8ToWString(resolved).c_str(), nullptr, &pidl, 0, &flags); @@ -174,8 +174,8 @@ std::string GetVideoCardDriverVersion() { IEnumWbemClassObject* pEnum; hr = pIWbemServices->ExecQuery(bstrWQL, bstrPath, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); - ULONG uReturned; - VARIANT var; + ULONG uReturned = 0; + VARIANT var{}; IWbemClassObject* pObj = NULL; if (!FAILED(hr)) { hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &uReturned); @@ -372,16 +372,8 @@ void System_SendMessage(const char *command, const char *parameter) { std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error")); MessageBox(MainWindow::GetHWND(), full_error.c_str(), title.c_str(), MB_OK); } else if (!strcmp(command, "setclipboardtext")) { - if (OpenClipboard(MainWindow::GetDisplayHWND())) { - std::wstring data = ConvertUTF8ToWString(parameter); - HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, (data.size() + 1) * sizeof(wchar_t)); - wchar_t *wstr = (wchar_t *)GlobalLock(handle); - memcpy(wstr, data.c_str(), (data.size() + 1) * sizeof(wchar_t)); - GlobalUnlock(wstr); - SetClipboardData(CF_UNICODETEXT, handle); - GlobalFree(handle); - CloseClipboard(); - } + std::wstring data = ConvertUTF8ToWString(parameter); + W32Util::CopyTextToClipboard(MainWindow::GetDisplayHWND(), data); } else if (!strcmp(command, "browse_file")) { MainWindow::BrowseAndBoot(""); } else if (!strcmp(command, "browse_folder")) { @@ -411,6 +403,8 @@ void EnableCrashingOnCrashes() { const DWORD EXCEPTION_SWALLOWING = 0x1; HMODULE kernel32 = LoadLibrary(L"kernel32.dll"); + if (!kernel32) + return; tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, @@ -773,7 +767,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin break; } - if (!TranslateAccelerator(wnd, accel, &msg)) { + if (!wnd || !accel || !TranslateAccelerator(wnd, accel, &msg)) { if (!DialogManager::IsDialogMessage(&msg)) { //and finally translate and dispatch TranslateMessage(&msg); @@ -782,8 +776,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin } } - MainThread_Stop(); - VFSShutdown(); MainWindow::DestroyDebugWindows(); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index c04801767e..40a9d9cc6d 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -547,15 +547,12 @@ BEGIN MENUITEM "Ignore Windows Key", ID_OPTIONS_IGNOREWINKEY MENUITEM "Language...", ID_OPTIONS_LANGUAGE MENUITEM "Control Mapping...", ID_OPTIONS_CONTROLS - MENUITEM "Display Layout Editor", ID_OPTIONS_DISPLAY_LAYOUT + MENUITEM "Display Layout && Effects", ID_OPTIONS_DISPLAY_LAYOUT MENUITEM "More Settings...", ID_OPTIONS_MORE_SETTINGS MENUITEM "", 0, MFT_SEPARATOR MENUITEM "Fullscreen", ID_OPTIONS_FULLSCREEN MENUITEM "VSync", ID_OPTIONS_VSYNC - POPUP "Postprocessing Shader", ID_OPTIONS_SHADER_MENU - BEGIN - MENUITEM "", 0, MFT_SEPARATOR - END + MENUITEM "Skip Buffer Effects", ID_OPTIONS_SKIP_BUFFER_EFFECTS POPUP "Rendering Resolution", ID_OPTIONS_SCREEN_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_SCREENAUTO @@ -592,11 +589,7 @@ BEGIN MENUITEM "Vulkan", ID_OPTIONS_VULKAN END - POPUP "Rendering Mode", ID_OPTIONS_RENDERMODE_MENU - BEGIN - MENUITEM "Non-Buffered Rendering", ID_OPTIONS_NONBUFFEREDRENDERING - MENUITEM "Buffered Rendering", ID_OPTIONS_BUFFEREDRENDERING - END + POPUP "Frame Skipping", ID_OPTIONS_FRAMESKIP_MENU BEGIN MENUITEM "Auto", ID_OPTIONS_FRAMESKIP_AUTO diff --git a/Windows/resource.h b/Windows/resource.h index ab68ee494f..83ef889573 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -118,8 +118,6 @@ #define IDC_GEDBG_PRIMCOUNTER 1201 #define IDC_BUTTON_SEARCH 1204 -#define ID_SHADERS_BASE 5000 - #define ID_FILE_EXIT 40000 #define ID_DEBUG_SAVEMAPFILE 40001 #define ID_DISASM_RUNTOHERE 40004 @@ -189,7 +187,7 @@ #define ID_DISASM_THREAD_KILL 40073 #define ID_FILE_SAVESTATE_NEXT_SLOT 40074 #define ID_FILE_SAVESTATE_NEXT_SLOT_HC 40075 -#define ID_OPTIONS_NONBUFFEREDRENDERING 40078 +#define ID_OPTIONS_SKIP_BUFFER_EFFECTS 40078 #define ID_OPTIONS_FRAMESKIP_0 40079 #define ID_OPTIONS_FRAMESKIP_1 40080 #define ID_OPTIONS_FRAMESKIP_2 40081 @@ -219,7 +217,6 @@ #define ID_OPTIONS_WINDOW3X 40106 #define ID_OPTIONS_WINDOW4X 40107 #define ID_OPTIONS_WINDOW5X 40108 -#define ID_OPTIONS_BUFFEREDRENDERING 40109 #define ID_DEBUG_SHOWDEBUGSTATISTICS 40110 #define ID_OPTIONS_SCREEN6X 40111 #define ID_OPTIONS_SCREEN7X 40112 diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index bee1ccda15..7ce80a7a45 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -70,37 +70,28 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/build.gradle b/android/build.gradle index 47eef16fd7..94dfd3bf80 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -45,6 +45,8 @@ android { } } compileSdkVersion 32 + ndkVersion "21.4.7075529" + defaultConfig { applicationId 'org.ppsspp.ppsspp' if (androidGitVersion.name() != "unknown" && androidGitVersion.code() >= 14000000) { @@ -149,7 +151,7 @@ android { } } vr_pico { - applicationId 'org.ppsspp.ppsspp' + applicationId 'org.ppsspp.ppssppvr' dimension "variant" externalNativeBuild { cmake { @@ -169,7 +171,7 @@ android { } } vr_quest { - applicationId 'org.ppsspp.ppsspp' + applicationId 'org.ppsspp.ppssppvr' dimension "variant" externalNativeBuild { cmake { diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 305caf67a5..5168e0c8d7 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -56,6 +56,7 @@ VULKAN_FILES := \ $(SRC)/Common/GPU/Vulkan/VulkanContext.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanDebug.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanImage.cpp \ + $(SRC)/Common/GPU/Vulkan/VulkanFramebuffer.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanMemory.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanProfiler.cpp \ $(SRC)/Common/GPU/Vulkan/VulkanBarrier.cpp @@ -71,6 +72,15 @@ SPIRV_CROSS_FILES := \ $(SRC)/ext/SPIRV-Cross/spirv_parser.cpp \ $(SRC)/ext/SPIRV-Cross/spirv_cross_parsed_ir.cpp +VR_FILES := \ + $(SRC)/Common/VR/OpenXRLoader.cpp \ + $(SRC)/Common/VR/PPSSPPVR.cpp \ + $(SRC)/Common/VR/VRBase.cpp \ + $(SRC)/Common/VR/VRFramebuffer.cpp \ + $(SRC)/Common/VR/VRInput.cpp \ + $(SRC)/Common/VR/VRMath.cpp \ + $(SRC)/Common/VR/VRRenderer.cpp + EXT_FILES := \ $(SRC)/ext/cityhash/city.cpp \ $(SRC)/ext/libpng17/png.c \ @@ -115,6 +125,7 @@ EXEC_AND_LIB_FILES := \ $(ARCH_FILES) \ $(EGL_FILES) \ $(VULKAN_FILES) \ + $(VR_FILES) \ $(VMA_FILES) \ $(SPIRV_CROSS_FILES) \ $(EXT_FILES) \ @@ -156,6 +167,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/GPU/Shader.cpp \ $(SRC)/Common/GPU/ShaderWriter.cpp \ $(SRC)/Common/GPU/ShaderTranslation.cpp \ + $(SRC)/Common/Render/ManagedTexture.cpp \ $(SRC)/Common/Render/DrawBuffer.cpp \ $(SRC)/Common/Render/TextureAtlas.cpp \ $(SRC)/Common/Render/Text/draw_text.cpp \ @@ -182,6 +194,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/Thread/ThreadUtil.cpp \ $(SRC)/Common/Thread/ThreadManager.cpp \ $(SRC)/Common/Thread/ParallelLoop.cpp \ + $(SRC)/Common/UI/AsyncImageFileView.cpp \ $(SRC)/Common/UI/Root.cpp \ $(SRC)/Common/UI/Screen.cpp \ $(SRC)/Common/UI/UI.cpp \ @@ -575,6 +588,12 @@ LIBARMIPS_FILES := \ $(SRC)/ext/armips/Archs/MIPS/MipsOpcodes.cpp \ $(SRC)/ext/armips/Archs/MIPS/MipsParser.cpp \ $(SRC)/ext/armips/Archs/MIPS/PsxRelocator.cpp \ + $(SRC)/ext/armips/Archs/SuperH/CShInstruction.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShElfRelocator.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShExpressionFunctions.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShOpcodes.cpp \ + $(SRC)/ext/armips/Archs/SuperH/ShParser.cpp \ + $(SRC)/ext/armips/Archs/SuperH/SuperH.cpp \ $(SRC)/ext/armips/Archs/Architecture.cpp \ $(SRC)/ext/armips/Commands/CAssemblerCommand.cpp \ $(SRC)/ext/armips/Commands/CAssemblerLabel.cpp \ @@ -671,7 +690,6 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/DiscordIntegration.cpp \ $(SRC)/UI/ChatScreen.cpp \ $(SRC)/UI/DevScreens.cpp \ - $(SRC)/UI/DisplayLayoutEditor.cpp \ $(SRC)/UI/DisplayLayoutScreen.cpp \ $(SRC)/UI/EmuScreen.cpp \ $(SRC)/UI/MainScreen.cpp \ @@ -697,7 +715,6 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/OnScreenDisplay.cpp \ $(SRC)/UI/ProfilerDraw.cpp \ $(SRC)/UI/NativeApp.cpp \ - $(SRC)/UI/TextureUtil.cpp \ $(SRC)/UI/Theme.cpp \ $(SRC)/UI/ComboKeyMappingScreen.cpp @@ -723,6 +740,18 @@ ifeq ($(HEADLESS),1) include $(BUILD_EXECUTABLE) endif +ifeq ($(OPENXR),1) + LOCAL_CFLAGS += -DOPENXR +endif + +ifeq ($(OPENXR_PLATFORM_QUEST),1) + LOCAL_CFLAGS += -DOPENXR_PLATFORM_QUEST +endif + +ifeq ($(OPENXR_PLATFORM_PICO),1) + LOCAL_CFLAGS += -DOPENXR_PLATFORM_PICO +endif + ifeq ($(UNITTEST),1) include $(CLEAR_VARS) include $(LOCAL_PATH)/Locals.mk diff --git a/android/jni/AndroidEGLContext.cpp b/android/jni/AndroidEGLContext.cpp index 9507c217e6..0cddc2b7f3 100644 --- a/android/jni/AndroidEGLContext.cpp +++ b/android/jni/AndroidEGLContext.cpp @@ -47,7 +47,7 @@ bool AndroidEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int des } gl->MakeCurrent(); if (gl->GetMode() == GLInterfaceMode::MODE_OPENGL) - SetGLCoreContext(!IsVRBuild()); + SetGLCoreContext(!IsVREnabled()); CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); SetGPUBackend(GPUBackend::OPENGL); diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp index c435ee4451..f7f7b70444 100644 --- a/android/jni/AndroidJavaGLContext.cpp +++ b/android/jni/AndroidJavaGLContext.cpp @@ -13,13 +13,18 @@ AndroidJavaEGLGraphicsContext::AndroidJavaEGLGraphicsContext() { bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { INFO_LOG(G3D, "AndroidJavaEGLGraphicsContext::InitFromRenderThread"); CheckGLExtensions(); + // OpenGL handles rotated rendering in the driver. g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); draw_ = Draw::T3DCreateGLContext(); // Can't fail renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager_->SetInflightFrames(g_Config.iInflightFrames); - draw_->CreatePresets(); + + if (!draw_->CreatePresets()) { + _assert_msg_(false, "Failed to compile preset shaders"); + return false; + } return true; } diff --git a/android/jni/Locals.mk b/android/jni/Locals.mk index ef0d118462..beed008585 100644 --- a/android/jni/Locals.mk +++ b/android/jni/Locals.mk @@ -15,6 +15,7 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../../ext/miniupnp-build \ $(LOCAL_PATH)/../../ext/libpng17 \ $(LOCAL_PATH)/../../ext/libzip \ + $(LOCAL_PATH)/../../ext/openxr \ $(LOCAL_PATH)/../../ext/zstd/lib \ $(LOCAL_PATH)/../../ext/armips \ $(LOCAL_PATH)/../../ext/armips/ext/filesystem/include \ diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 98e1ca6052..a79f558285 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -13,9 +13,8 @@ #include #include -#include - #ifndef _MSC_VER + #include #include #include @@ -198,38 +197,53 @@ AndroidGraphicsContext *graphicsContext; #define LOG_APP_NAME "PPSSPP" #endif -#ifdef _DEBUG -#define DLOG(...) __android_log_print(ANDROID_LOG_INFO, LOG_APP_NAME, __VA_ARGS__); -#else -#define DLOG(...) -#endif - -#define ILOG(...) __android_log_print(ANDROID_LOG_INFO, LOG_APP_NAME, __VA_ARGS__); -#define WLOG(...) __android_log_print(ANDROID_LOG_WARN, LOG_APP_NAME, __VA_ARGS__); -#define ELOG(...) __android_log_print(ANDROID_LOG_ERROR, LOG_APP_NAME, __VA_ARGS__); -#define FLOG(...) __android_log_print(ANDROID_LOG_FATAL, LOG_APP_NAME, __VA_ARGS__); - #define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c)); +#if PPSSPP_ARCH(ARMV7) +// Old Android workaround +extern "C" { +int utimensat(int fd, const char *path, const struct timespec times[2]) { + return -1; +} +} +#endif + void AndroidLogger::Log(const LogMessage &message) { - // Log with simplified headers as Android already provides timestamp etc. + int mode; switch (message.level) { - case LogTypes::LVERBOSE: - case LogTypes::LDEBUG: - case LogTypes::LINFO: - ILOG("[%s] %s", message.log, message.msg.c_str()); + case LogTypes::LWARNING: + mode = ANDROID_LOG_WARN; break; case LogTypes::LERROR: - ELOG("[%s] %s", message.log, message.msg.c_str()); + mode = ANDROID_LOG_ERROR; break; - case LogTypes::LWARNING: - WLOG("[%s] %s", message.log, message.msg.c_str()); - break; - case LogTypes::LNOTICE: default: - ILOG("[%s] !!! %s", message.log, message.msg.c_str()); + mode = ANDROID_LOG_INFO; break; } + + // Long log messages need splitting up. + // Not sure what the actual limit is (seems to vary), but let's be conservative. + const size_t maxLogLength = 512; + if (message.msg.length() < maxLogLength) { + // Log with simplified headers as Android already provides timestamp etc. + __android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, message.msg.c_str()); + } else { + std::string msg = message.msg; + + // Ideally we should split at line breaks, but it's at least fairly usable anyway. + std::string first_part = msg.substr(0, maxLogLength); + __android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, first_part.c_str()); + msg = msg.substr(maxLogLength); + + while (msg.length() > maxLogLength) { + std::string first_part = msg.substr(0, maxLogLength); + __android_log_print(mode, LOG_APP_NAME, "%s", first_part.c_str()); + msg = msg.substr(maxLogLength); + } + // Print the final part. + __android_log_print(mode, LOG_APP_NAME, "%s", msg.c_str()); + } } JNIEnv* getEnv() { @@ -280,7 +294,12 @@ static void EmuThreadFunc() { } else { INFO_LOG(SYSTEM, "Runloop: Graphics context available! %p", graphicsContext); } - NativeInitGraphics(graphicsContext); + + if (!NativeInitGraphics(graphicsContext)) { + _assert_msg_(false, "Failed to initialize graphics, might as well bail"); + emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; + return; + } INFO_LOG(SYSTEM, "Graphics initialized. Entering loop."); @@ -757,9 +776,10 @@ retry: EmuThreadStart(); } - if (IsVRBuild()) { + if (IsVREnabled()) { Version gitVer(PPSSPP_GIT_VERSION); - InitVROnAndroid(gJvm, nativeActivity, gitVer.ToInteger(), "PPSSPP"); + InitVROnAndroid(gJvm, nativeActivity, systemName.c_str(), gitVer.ToInteger(), "PPSSPP"); + SetVRCallbacks(NativeAxis, NativeKey, NativeTouch); } } @@ -939,8 +959,8 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, } NativeMessageReceived("recreateviews", ""); - if (IsVRBuild()) { - EnterVR(firstStart); + if (IsVREnabled()) { + EnterVR(firstStart, graphicsContext->GetAPIContext()); } return true; @@ -982,7 +1002,7 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv pixel_yres = bufh; backbuffer_format = format; - if (IsVRBuild()) { + if (IsVREnabled()) { GetVRResolutionPerEye(&pixel_xres, &pixel_yres); } @@ -1057,7 +1077,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, SetCurrentThreadName("AndroidRender"); } - if (IsVRBuild() && !StartVRRender()) + if (IsVREnabled() && !StartVRRender()) return; if (useCPUThread) { @@ -1068,8 +1088,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, UpdateRunLoopAndroid(env); } - if (IsVRBuild()) { - UpdateVRInput(NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale); + if (IsVREnabled()) { + UpdateVRInput(g_Config.bHapticFeedback, dp_xscale, dp_yscale); FinishVRRender(); } } @@ -1291,11 +1311,11 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) { extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) { INFO_LOG(G3D, "NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate); - if (IsVRBuild()) { + if (IsVREnabled()) { int width, height; GetVRResolutionPerEye(&width, &height); xres = width; - yres = height; + yres = height * 272 / 480; dpi = 320; } diff --git a/android/src/org/ppsspp/ppsspp/CameraHelper.java b/android/src/org/ppsspp/ppsspp/CameraHelper.java index d324d50819..9fdb270606 100644 --- a/android/src/org/ppsspp/ppsspp/CameraHelper.java +++ b/android/src/org/ppsspp/ppsspp/CameraHelper.java @@ -159,6 +159,9 @@ class CameraHelper { static ArrayList getDeviceList() { ArrayList deviceList = new ArrayList<>(); + if (NativeActivity.isVRDevice()) { + return deviceList; + } int nrCam = Camera.getNumberOfCameras(); for (int index = 0; index < nrCam; index++) { try { diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 5de8a70b77..07a80dae19 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -1235,6 +1235,12 @@ public abstract class NativeActivity extends Activity { // The return value is sent to C++ via seqID. public void inputBox(final String seqID, final String title, String defaultText, String defaultAction) { + // Workaround for issue #13363 to fix Split/Second game start + if (isVRDevice()) { + NativeApp.sendInputBox(seqID, false, defaultText); + return; + } + final FrameLayout fl = new FrameLayout(this); final EditText input = new EditText(this); input.setGravity(Gravity.CENTER); @@ -1551,7 +1557,7 @@ public abstract class NativeActivity extends Activity { } } - private boolean isVRDevice() { + public static boolean isVRDevice() { return BuildConfig.FLAVOR.startsWith("vr_"); } } diff --git a/assets/compat.ini b/assets/compat.ini index 478cef073e..9cd27be8d8 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -622,6 +622,8 @@ ULJM05570 = true # Cars Race-o-rama ULUS10428 = true +ULES01333 = true + # MX vs ATV Reflex ULES01375 = true ULUS10429 = true @@ -678,6 +680,12 @@ ULJS00233 = true NPJH90089 = true # (demo) NPJH90065 = true # Unknown +# Colin McRae 2005 (sun effect, see #7810) +ULES00111 = true +ULKS46010 = true +ULJM05223 = true +ULJM05362 = true + # Note! This whole flag is disabled temporarily by appending "Disabled" to its name). See 7914 [YugiohSaveFixDisabled] # The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat, @@ -1216,6 +1224,59 @@ ULJM05494 = true NPJH50143 = true ULJM05738 = true +# Motorstorm - See #16429 +UCES01250 = true +UCAS40266 = true +UCUS98743 = true +UCES01250 = true +UCKS45124 = true +UCJS10104 = true +NPJG00047 = true + +[ForceLowerResolutionForEffectsOff] +# Some games really don't work with this. Ratchet & Clank looks terrible. +UCUS98633 = true +UCAS40145 = true +UCES00420 = true +UCJS10052 = true +UCKS45048 = true +UCES00420 = true +UCJS18030 = true +UCJS18047 = true +NPJG00015 = true + +# The various Tantalus games will not work with this. + +# Cars Race-o-rama +ULUS10428 = true +ULES01333 = true + +# MX vs ATV Reflex +ULES01375 = true +ULUS10429 = true + +# MX vs ATV Untamed +ULUS10330 = true +ULES00993 = true +ULKS46176 = true + +# Spongebob: The Yellow Avenger +ULES00280 = true +ULUS10092 = true + +# Also, it's a really bad idea in Kurohyou. + +# Kurohyou: Ryu ga Gotoku Shinshou +ULJM05713 = true +NPJH50333 = true +ULAS42244 = true +UCKS45159 = true +ULJM08047 = true + +# Kurohyou 2: Ryu ga Gotoku Ashura Hen (Japan) +NPJH50562 = true +NPJH50333 = true + [NearestFilteringOnFramebufferCreate] # Ridge Racer speedometer dynamic CLUT problem - they rely on some palette entries # from memory, and render to the rest of the palette. The palette entries loaded from memory @@ -1241,8 +1302,112 @@ NPJH50366 = true # Temporary compatibility option, while working on the GPU CLUT-from-framebuffer path. # Not required for any games now that it works, but might be useful for development. +[SecondaryTextureCache] +# Was previously the "Retain changed textures" setting. +# See https://github.com/hrydgard/ppsspp/issues/16339#issuecomment-1304826656 + +# Popolocrois +UCJS10005 = true +UCAS40009 = true +ULUS10018 = true +UCJS18003 = true +ULES00291 = true +NPJG00033 = true + +# Fushigi no Dungeon: Fuurai no Shiren 4 Plus - Kami no Hitomi to Akuma no Heso +ULJS00547 = true +NPJH50698 = true + +# Final Fantasy Tactics +UCAS40148 = true +ULJM05194 = true +ULES00850 = true +ULUS10297 = true +ULJM05516 = true +NPJH50408 = true + +[EnglishOrJapaneseOnly] +# Twinbee Portable, see issue #16382 +ULAS42089 = true +ULJM05221 = true +ULJM05323 = true + +[OldAdrenoPixelDepthRoundingGL] +# See #16015 + +# Naruto Shippuden: Ultimate Ninja Impact +ULUS10582 = true +ULES01537 = true +ULJS00390 = true +ULAS42297 = true +ULJS19071 = true +NPJH50435 = true +NPJH50435 = true + +# Kingdom Hearts - Birth By Sleep +ULES01441 = true +ULJM05600 = true +ULUS10505 = true +ULJM05775 = true # Final MIX +PSPJ30012 = true +UCAS40295 = true +UCKS45143 = true +UCAS40317 = true +UCAS40326 = true +UCKS45168 = true +ULJM06213 = true +ULJM06214 = true + +# Monster Hunter Portable 3rd +NPJB40001 = true +NPJH55800 = true +ULJM05800 = true +ULJM08058 = true + +# Persona 3 Portable +ULES01523 = true +ULUS10512 = true +UCAS40288 = true +ULJM05489 = true +UCKS45140 = true +ULJM08044 = true +NPJH50040 = true +UCKS45175 = true + +# Hack/Link +ULJS00266 = true +ULJS00279 = true +ULJS19058 = true + +# Midnight Club: LA Remix +ULUS10383 = true +ULES01144 = true +ULJS00180 = true +ULJS00267 = true +ULJM05904 = true +NPJH50440 = true + +# ModNation Racers +UCES01327 = true +UCUS98741 = true +UCAS40306 = true +UCJS10112 = true +NPJG00116 = true +NPUG70097 = true # Demo + +[ForceCircleButtonConfirm] +# Shining Ark, issue #15663 +NPJH50717 = true +ULJM06223 = true + +[DisallowFramebufferAtOffset] +# Little Big Planet, see #16030 +UCUS98744 = true +UCES01264 = true +UCJS10107 = true +NPJG00073 = true +UCAS40262 = true [Fontltn12Hack] #optimumFont do not return ltn12.pgf see #11055 -NPJH00052 = true - +NPJH00052 = true \ No newline at end of file diff --git a/assets/compatvr.ini b/assets/compatvr.ini index c3ec3f926a..b896196ab8 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -30,315 +30,522 @@ # ======================================================================================== +[IdentityViewHack] +# Disables head tracking for render passes where view matrix is Identity + +# Sonic Rivals 1 +ULES00622 = true +ULUS10195 = true + +# Sonic Rivals 2 +ULES00940 = true +ULUS10323 = true + + [Skyplane] +# Workaround to remove the background skyplane and add clearing framebuffer with a fog color. + # Grand Theft Auto: Liberty City Stories -ULUS10041 = true +NPJH50825 = true +ULES00051 = true ULES00151 = true +ULES00181 = true +ULES00182 = true ULJM05255 = true ULJM05359 = true ULJM05885 = true -NPJH50825 = true +ULUS10041 = true # Grand Theft Auto: Vice City Stories +NPJH50827 = true ULES00502 = true -ULUS10160 = true +ULES00503 = true ULJM05297 = true ULJM05395 = true ULJM05884 = true -NPJH50827 = true +ULUS10160 = true + [UnitsPerMeter] -# Values exported from https://github.com/CarlKenner/ppsspp/tree/VR/Sys/GameSettings +# Scale of game world to convert the world units into meters. This enables following VR features: +# + 3D stereoscopy (that can work only with accurate values) +# * 6DoF motion tracking (that can work with inaccurate values) + +# cube.elf ELF000000 = 10.0 -JRPG00001 = 80 -JRPG00002 = 80 -NPEG00001 = 1.0 -NPEG00003 = 1000.0 -NPEG00023 = 1.0 -NPEG90003 = 1.0 -NPEH00003 = 30.0 -NPEH00017 = 1.0 -NPEH00031 = 1.0 -NPEH00134 = 8.0 -NPEH00135 = 1.0 -NPEH00138 = 80 -NPEH90011 = 100.0 -NPEH90014 = 1.0 -NPEH90023 = 1000.0 -NPEH90028 = 128.0 -NPEX00005 = 1.0 -NPEZ00007 = 1.0 -NPEZ00008 = 20.0 -NPEZ00011 = 1.0 -NPEZ00023 = 1.0 -NPEZ00041 = 1.0 -NPEZ00044 = 1.0 -NPEZ00045 = 1.0 -NPEZ00081 = 1.0 -NPEZ00101 = 1.0 -NPEZ00104 = 1.0 -NPEZ00107 = 1.0 -NPEZ00108 = 1.0 -NPEZ00118 = 70.0 -NPEZ00127 = 1.0 -NPEZ00140 = 1.0 -NPHG00002 = 1.0 -NPHG00025 = 80.0 -NPHH00351 = 8.0 -NPJB40001 = 100.0 -NPJG00004 = 1000.0 -NPJG00045 = 80.0 -NPJG00103 = 1.0 -NPJG00122 = 100.0 -NPJH00002 = 30.0 -NPJH50040 = 1.0 -NPJH50045 = 1000.0 -NPJH50065 = 1.0 -NPJH50145 = 9.0 -NPJH50148 = 1.0 -NPJH50180 = 1.0 -NPJH50184 = 1000.0 -NPJH50352 = 100 -NPJH50401 = 1.0 -NPJH50414 = 1.0 -NPJH50443 = 100.0 -NPJH50444 = 100.0 -NPJH50448 = 80 -NPJH50457 = 1.0 -NPJH50475 = 4.0 -NPJH50515 = 8.0 -NPJH50625 = 1.8 -NPJH50626 = 8.0 -NPJH50701 = 1.0 -NPJH90066 = 1.0 -NPUG70008 = 1.0 -NPUG80086 = 1000.0 -NPUG80325 = 1.0 -NPUH10006 = 30.0 -NPUH10023 = 1.0 -NPUH10024 = 1.0 -NPUH10026 = 1.0 -NPUH10034 = 1.0 -NPUH10125 = 8.0 -NPUH10126 = 80 -NPUH90019 = 1.0 -NPUH90029 = 1.0 -NPUH90048 = 1.0 -NPUH90067 = 128.0 -NPUX80433 = 1.0 -NPUZ00002 = 1.0 -NPUZ00007 = 1.0 -NPUZ00010 = 1.0 -NPUZ00020 = 1.0 -NPUZ00021 = 1.0 -NPUZ00024 = 1.0 -NPUZ00027 = 20.0 -NPUZ00028 = 1.0 -NPUZ00031 = 1.0 -NPUZ00033 = 70.0 -NPUZ00034 = 1.0 -NPUZ00040 = 1.0 -NPUZ00056 = 1.0 -NPUZ00080 = 1.0 -UCAS40011 = 1.0 -UCAS40012 = 1.0 -UCAS40018 = 9.0 -UCAS40020 = 100.0 -UCAS40021 = 10.0 -UCAS40023 = 9.0 -UCAS40024 = 0.98 -UCAS40025 = 83 -UCAS40026 = 0.1 -UCAS40049 = 1.0 -UCAS40063 = 1.0 -UCAS40076 = 5.0 -UCAS40089 = 9.0 -UCAS40092 = 100.0 -UCAS40095 = 1000.0 -UCAS40098 = 0.96 -UCAS40099 = 1000.0 -UCAS40102 = 1.0 -UCAS40113 = 1000.0 -UCAS40116 = 9.0 -UCAS40119 = 1000.0 + +# 300: March to Glory +ULES00766 = 0.95 +ULUS10241 = 0.95 + +# 50 Cent: Bulletproof G Unit Edition +ULES00451 = 1.0 +ULES00452 = 1.0 +ULUS10128 = 1.0 + +# 7 Wonders of the Ancient World +ULES01037 = 1.0 +ULUS10227 = 1.0 + +# Ace Combat X: Skies of Deception UCAS40120 = 1.0 -UCAS40129 = 7.0 -UCAS40130 = 0.98 -UCAS40145 = 1.0 -UCAS40146 = 6.8 -UCAS40148 = 1.0 -UCAS40149 = 0.96 -UCAS40156 = 9.0 -UCAS40164 = 1000.0 -UCAS40165 = 1000.0 -UCAS40167 = 100.0 UCAS40169 = 1.0 -UCAS40177 = 0.96 -UCAS40179 = 1.0 -UCAS40180 = 9.5 -UCAS40191 = 1.0 -UCAS40193 = 80.0 -UCAS40198 = 1.0 -UCAS40204 = 100.0 -UCAS40212 = 1.0 -UCAS40258 = 0.96 -UCAS40265 = 1.0 -UCAS40318 = 100.0 -UCED00432 = 1.0 -UCED00448 = 1000.0 -UCED00970 = 1.0 -UCED00971 = 1.0 -UCED90007 = 1.0 -UCES00001 = 1.0 -UCES00004 = 0.1 -UCES00010 = 100.0 -UCES00044 = 2.0 -UCES00109 = 5.0 -UCES00178 = 9.0 -UCES00249 = 1.0 -UCES00302 = 100.0 -UCES00304 = 1.0 -UCES00356 = 1000.0 -UCES00420 = 1.0 -UCES00422 = 1000.0 UCES00423 = 1.0 -UCES00465 = 1.0 -UCES00842 = 1.0 -UCES00995 = 80.0 -UCES01245 = 1.0 -UCES01312 = 80.0 -UCES01401 = 1.0 -UCES01421 = 100.0 -UCES01473 = 1.0 -UCET00179 = 5.0 -UCET00247 = 9.0 -UCET00357 = 1.0 -UCET00424 = 1000.0 -UCET00713 = 1.0 -UCJB98011 = 1.0 -UCJM95402 = 9.0 -UCJS10007 = 1.0 -UCJS10008 = 1.0 -UCJS10010 = 9.0 -UCJS10011 = 10.0 -UCJS10017 = 0.98 -UCJS10018 = 83 -UCJS10019 = 0.1 -UCJS10028 = 5.0 -UCJS10041 = 1.0 -UCJS10042 = 0.96 -UCJS10047 = 9.0 -UCJS10048 = 7.0 -UCJS10052 = 1.0 -UCJS10057 = 0.96 -UCJS10061 = 9.5 -UCJS10077 = 80.0 -UCJS10082 = 0.96 -UCJS10085 = 1.0 -UCJS10092 = 1.0 -UCJS10093 = 0.96 -UCJS10100 = 1.0 -UCJS10106 = 1.0 -UCJS10114 = 1.0 -UCJS18005 = 1.0 -UCJS18010 = 0.98 -UCJS18014 = 7.0 -UCJS18015 = 0.96 -UCJX90019 = 7.0 -UCKS45007 = 10.0 -UCKS45008 = 1.0 -UCKS45011 = 9.0 -UCKS45018 = 1.0 -UCKS45020 = 1.0 -UCKS45022 = 1.0 -UCKS45027 = 1000.0 -UCKS45032 = 1000.0 -UCKS45034 = 9.0 UCKS45038 = 1.0 -UCKS45050 = 10.0 -UCKS45052 = 100.0 -UCKS45056 = 6.8 UCKS45067 = 1.0 -UCKS45071 = 9.5 -UCKS45076 = 80.0 -UCKS45120 = 1.0 -UCUS98612 = 1.0 -UCUS98618 = 2.0 -UCUS98623 = 9.0 -UCUS98632 = 1.0 -UCUS98633 = 1.0 -UCUS98647 = 5.0 -UCUS98648 = 1.0 -UCUS98653 = 1.0 -UCUS98654 = 2.0 -UCUS98662 = 1.0 -UCUS98671 = 5.0 -UCUS98681 = 1.0 -UCUS98700 = 7.0 -UCUS98706 = 7.0 -UCUS98711 = 80.0 -UCUS98712 = 1.0 -UCUS98713 = 1.0 -UCUS98717 = 80.0 -UCUS98732 = 80.0 -UCUS98737 = 1.0 -UCUS98740 = 80.0 -UCUS98751 = 100.0 -ULAS40129 = 7.0 -ULAS40155 = 1.0 -ULAS42007 = 1000.0 -ULAS42019 = 1.0 -ULAS42035 = 930.0 -ULAS42037 = 1.0 -ULAS42052 = 10.0 -ULAS42069 = 7.8 -ULAS42072 = 1.0 -ULAS42073 = 7.8 -ULAS42087 = 970.0 -ULAS42093 = 100.0 -ULAS42097 = 10.0 -ULAS42099 = 1.0 -ULAS42110 = 100.0 -ULAS42115 = 1.0 -ULAS42117 = 1.0 -ULAS42119 = 1.0 -ULES00008 = 1000.0 +ULJS00086 = 1.0 +ULJS19018 = 1.0 +ULUS10176 = 1.0 + +# Activision Hits Remixed +ULES00640 = 1.0 +ULUS10186 = 1.0 + +# Age of Zombies +NPEZ00044 = 1.0 +NPUZ00024 = 1.0 + +# Alien Syndrome +ULES00772 = 1.0 +ULUS10245 = 1.0 + +# Ape Escape Academy +NPJG00048 = 100.0 +UCAS40007 = 100.0 +UCES00010 = 100.0 +UCJS10003 = 100.0 +UCJS18007 = 100.0 +UCJS18043 = 100.0 +UCUS98619 = 100.0 + +# Ape Escape Academy 2 +NPJG00049 = 100.0 +UCAS40041 = 100.0 +UCAS40052 = 100.0 +UCAS40123 = 100.0 +UCES00302 = 100.0 +UCJS10020 = 100.0 +UCJS18009 = 100.0 +UCKS45024 = 100.0 + +# Archer Maclean's Mercury +UCAS40021 = 10.0 +UCJS10011 = 10.0 +UCKS45007 = 10.0 ULES00011 = 10.0 -ULES00026 = 0.1 -ULES00033 = 0.005 -ULES00034 = 0.005 -ULES00035 = 0.005 -ULES00051 = 1.0 -ULES00118 = 0.1 -ULES00119 = 0.1 -ULES00125 = 1.0 -ULES00126 = 10.0 -ULES00135 = 83 -ULES00144 = 1.0 -ULES00151 = 1.0 -ULES00153 = 83 +ULUS10017 = 10.0 + +# Are You Alice? +AAPP11042 = 1.0 +ULJM05848 = 1.0 + +# Army of Two: The 40th Day +NPEH90028 = 128.0 +NPUH90067 = 128.0 +ULAS42215 = 128.0 +ULES01381 = 128.0 +ULJM05643 = 128.0 +ULJM05849 = 128.0 +ULUS10472 = 128.0 + +# Armored Core 3 Portable +NPEH00045 = 1.0 +NPUH10023 = 1.0 +UCAS40268 = 1.0 +ULJM05492 = 1.0 +ULKS46210 = 1.0 + +# Armored Core: Formula Front - Extreme Battle +NPJH50041 = 1.0 +UCAS40004 = 1.0 +UCAS40036 = 1.0 +ULES00219 = 1.0 +ULJS00003 = 1.0 +ULJS19001 = 1.0 +ULKS46003 = 1.0 +ULUS10034 = 1.0 + +# Armored Core: Last Raven Portable +NPEH00046 = 1.0 +NPUH10024 = 1.0 +ULJM05611 = 1.0 +UCAS40302 = 1.0 +UCKS45148 = 1.0 + +# Assassin's Creed: Bloodlines +NPEH00029 = 1.0 +NPUH10032 = 1.0 +ULES01367 = 1.0 +ULKS46231 = 1.0 +ULJM05571 = 1.0 +ULJM05720 = 1.0 +ULUS10455 = 1.0 + +# Astonishia Story +ULES00363 = 1.0 +ULJM05176 = 1.0 +ULKS46021 = 1.0 +ULUS10083 = 1.0 + +# Atari Classics Evolved +ULUS10325 = 1.0 + +# ATV Offroad Fury Pro +UCES00786 = 1.0 +UCUS98648 = 1.0 +UCUS98681 = 1.0 + +# Audition Portable +ULKS46122 = 32.0 + +# B-Boy +UCED00432 = 1.0 +UCES00249 = 1.0 +ULUS10363 = 1.0 + +# Battle Poker +NPUZ00020 = 1.0 + +# BattleZone +ULES00522 = 1.0 +ULET00456 = 1.0 +ULUS10156 = 1.0 + +# Beam 'em up +NPEZ00081 = 1.0 + +# Beaterator +ULES01023 = 1.0 +ULUS10405 = 1.0 + +# Beats +NPEG00001 = 1.0 +NPHG00002 = 1.0 +NPJG00001 = 1.0 +NPUG80060 = 1.0 + +# Big head snooker +NPEZ00104 = 1.0 + +# Black Rock Shooter: The Game +JRPG00001 = 80.0 +JRPG00002 = 80.0 +NPEH00138 = 80.0 +NPJH50448 = 80.0 +NPUH10126 = 80.0 +ULJM05859 = 80.0 + +# Blast Off +NPEZ00041 = 1.0 +NPUZ00021 = 1.0 + +# BlazBlue: Calamity Trigger Portable +NPJH50180 = 1.0 +UCAS40299 = 1.0 +ULJM05613 = 1.0 +ULJM05970 = 1.0 +ULUS10519 = 1.0 + +# BlazBlue: Continuum Shift II +NPJH50401 = 1.0 +UCKS45170 = 1.0 +ULES01526 = 1.0 +ULJM05850 = 1.0 +ULUS10579 = 1.0 + +# Bleach: Heat the Soul 1 +UCAS40011 = 1.0 +UCJS18005 = 1.0 +UCJS10008 = 1.0 + +# Bleach: Heat the Soul 2 +UCAS40024 = 0.98 +UCAS40130 = 0.98 +UCJS18010 = 0.98 +UCJS10017 = 0.98 + +# Bleach: Heat the Soul 3 +UCAS40098 = 0.96 +UCAS40177 = 0.96 +UCJS10042 = 0.96 +UCJS18015 = 0.96 + +# Bleach: Heat the Soul 4 +UCAS40149 = 0.96 +UCAS40216 = 0.96 +UCJS10057 = 0.96 +UCJS18025 = 0.96 + +# Bleach: Heat the Soul 5 +UCAS40210 = 0.96 +UCJS10082 = 0.96 +UCJS18033 = 0.96 + +# Bleach: Heat the Soul 6 +NPJG00021 = 0.96 +UCAS40258 = 0.96 +UCAS40308 = 0.96 +UCJS10093 = 0.96 +UCJS18039 = 0.96 + +# Bleach: Heat the Soul 7 +NPJG00114 = 0.96 +UCAS40314 = 0.96 +UCJS10110 = 0.96 +UCJS18057 = 0.96 +UCKS45158 = 0.96 + +# Bleach: Soul Carnival 1 +NPJG00008 = 1.0 +UCAS40227 = 1.0 +UCAS40234 = 1.0 +UCAS40296 = 1.0 +UCJS10085 = 1.0 +UCJS18038 = 1.0 +UCKS45102 = 1.0 +ULJS10085 = 1.0 + +# Bleach: Soul Carnival 2 +NPJG00070 = 1.0 +UCJS10106 = 1.0 +UCAS40291 = 1.0 +UCAS40297 = 1.0 + +# Bloons +NPEZ00045 = 1.0 +NPUZ00010 = 1.0 + +# Bomberman Land Portable +NPJH50142 = 10.0 +ULAS42097 = 10.0 +ULES00959 = 10.0 +ULJM05181 = 10.0 +ULJM05319 = 10.0 +ULUS10319 = 10.0 + +# Bowling 3D +NPUZ00002 = 1.0 + +# Brain Challenge +NPEH00003 = 30.0 +NPJH00002 = 30.0 +NPUH10006 = 30.0 + +# BreakQuest +NPEZ00011 = 1.0 +NPUZ00031 = 1.0 + +# Bubble Trubble +NPEZ00023 = 1.0 +NPUZ00007 = 1.0 + +# Burnout Legends +ULES00125 = 2.0 +ULUS10025 = 2.0 +ULJM05228 = 2.0 +NPJH50305 = 2.0 +ULJM05049 = 2.0 +ULKS46027 = 2.0 +ULAS42019 = 2.0 + +# Bust-A-Move Deluxe +NPJH50087 = 1.0 +ULES00233 = 1.0 +ULUS10057 = 1.0 +ULJM05116 = 1.0 + +# Cabela's African Safari +ULUS10175 = 1.0 + +# Call of Duty: Roads to Victory +ULES00643 = 1.05 +ULES00644 = 1.05 +ULUS10218 = 1.05 + +# Capcom Classics Collection Reloaded +ULAS42072 = 1.0 +ULES00377 = 1.0 +ULJM05104 = 1.0 +ULJM05280 = 1.0 +ULUS10134 = 1.0 + +# Castlevania: The Dracula X Chronicles +NPJH50028 = 100.0 +ULES00841 = 100.0 +ULJM05287 = 100.0 +ULKS46155 = 100.0 +ULUS10277 = 100.0 + +# Championship Manager +ULES00174 = 1.0 + +# Charge! Tank Squad +NPEX00005 = 1.0 +NPJG00103 = 1.0 +NPUX80433 = 1.0 + +# Chessmaster: The Art of Learning +ULES01013 = 1.0 +ULUS10335 = 1.0 + +# Circles, Circles, Circles +NPEZ00007 = 1.0 +NPUZ00028 = 1.0 + +# Coded Arms: Contagion +ULAS42099 = 1.0 +ULES00718 = 1.0 +ULJM05243 = 1.0 +ULKS46139 = 1.0 +ULUS10184 = 1.0 + +# Coded Soul: Uketsugareshi Idea +NPJG00043 = 9.5 +UCAS40180 = 9.5 +UCJS10061 = 9.5 +UCKS45071 = 9.5 + +# Crash Tag Team Racing ULES00168 = 1.0 ULES00169 = 1.0 ULES00170 = 1.0 ULES00171 = 1.0 ULES00172 = 1.0 -ULES00174 = 1.0 -ULES00181 = 1.0 -ULES00182 = 1.0 -ULES00183 = 1.0 -ULES00210 = 1.0 -ULES00214 = 1.0 -ULES00215 = 1.0 -ULES00216 = 1.0 -ULES00219 = 1.0 -ULES00223 = 1.0 -ULES00227 = 10.0 -ULES00233 = 1.0 -ULES00235 = 1.0 -ULES00277 = 100.0 -ULES00283 = 256.0 -ULES00284 = 930.0 -ULES00307 = 10.0 +ULJM05036 = 1.0 +ULUS10044 = 1.0 + +# Crazy Taxi: Fare Wars +NPJH50490 = 10.0 +ULES00811 = 10.0 +ULJM05340 = 10.0 +ULUS10273 = 10.0 + +# Creature Defense +NPEH00027 = 1.0 +NPJH00006 = 1.0 +NPUH10034 = 1.0 + +# Crimson Gem Saga +UCAS40212 = 1.0 +ULJM05369 = 1.0 +ULKS46142 = 1.0 +ULUS10400 = 1.0 + +# Crimson Room Reverse +NPJH50046 = 32.0 +NPUH10037 = 32.0 +ULJM05408 = 32.0 + +# Crisis Core: Final Fantasy VII +UCAS40167 = 100.0 +UCAS40204 = 100.0 +UCAS40272 = 100.0 +UCKS45052 = 100.0 +ULES01044 = 100.0 +ULES01045 = 100.0 +ULES01046 = 100.0 +ULES01047 = 100.0 +ULJM05254 = 100.0 +ULJM05275 = 100.0 +ULJM05517 = 100.0 +ULUS10336 = 100.0 + +# Crush +ULES00765 = 1.0 +ULUS10238 = 1.0 + +# Crystal Defenders +NPEH00017 = 1.0 +NPJH00005 = 1.0 +NPJH90066 = 1.0 +NPUH10026 = 1.0 +NPUH90048 = 1.0 + +# Cube +ULES00722 = 10.0 +ULJS00108 = 10.0 +ULUS10223 = 10.0 + +# Cubixx +NPEZ00101 = 1.0 +NPUZ00080 = 1.0 + +# D-Cube Planet +NPEZ00008 = 20.0 +NPUZ00027 = 20.0 + +# Dangan-Ronpa +NPJH50515 = 8.0 +ULJS00337 = 8.0 +ULJS00438 = 8.0 +ULJS19060 = 8.0 + +# Daxter +NPEG00025 = 2.0 +UCES00044 = 2.0 +UCKS45025 = 2.0 +UCUS98618 = 2.0 +UCUS98654 = 2.0 + +# Dead or Alive Paradise +NPEH00038 = 0.8 +NPJH50239 = 0.8 +ULES01416 = 0.8 +ULES01431 = 0.8 +ULJM05640 = 0.8 +ULJM08046 = 0.8 +ULKS46246 = 0.8 +ULUS10521 = 0.8 + +# Death Jr. +ULES00144 = 1.0 +ULUS10027 = 1.0 + +# Deflector +NPEZ00127 = 1.0 +NPUZ00040 = 1.0 + +# Diamond and the Sound of a Gunshot +UCJS10092 = 1.0 +UCKS45120 = 1.0 + +# Dissidia 012: Duodecim Final Fantasy +NPJH50377 = 1.0 +UCAS40333 = 1.0 +UCAS40329 = 1.0 +UCAS40335 = 1.0 +UCKS45166 = 1.0 +ULES01505 = 1.0 +ULJM05814 = 1.0 +ULJM06121 = 1.0 +ULUS10566 = 1.0 + +# Dissidia: Final Fantasy +NPEH90014 = 1.0 +NPJH50065 = 1.0 +NPJH50330 = 1.0 +NPUH90029 = 1.0 +UCAS40322 = 1.0 +ULES01270 = 1.0 +ULJM05262 = 1.0 +ULJM05405 = 1.0 +ULJM05550 = 1.0 +ULJM05760 = 1.0 +ULJM05761 = 1.0 +ULUS10437 = 1.0 + +# Disney G-Force +ULES01238 = 1.0 +ULES01239 = 1.0 +ULES01240 = 1.0 +ULUS10439 = 1.0 + +# Disney Hannah Montana: Rock Out the Show +ULES01303 = 1.0 +ULUS10431 = 1.0 + +# Disney/Pixar Cars +UCKS45018 = 1.0 ULES00319 = 1.0 ULES00320 = 1.0 ULES00321 = 1.0 @@ -348,30 +555,11 @@ ULES00324 = 1.0 ULES00325 = 1.0 ULES00326 = 1.0 ULES00327 = 1.0 -ULES00339 = 1.0 -ULES00363 = 1.0 -ULES00377 = 1.0 -ULES00382 = 1.0 -ULES00383 = 50.0 -ULES00419 = 7.8 -ULES00452 = 1.0 -ULES00474 = 0.1 -ULES00475 = 0.1 -ULES00479 = 47.0 -ULES00484 = 1.0 -ULES00502 = 1.0 -ULES00503 = 1.0 -ULES00522 = 1.0 -ULES00567 = 1.0 -ULES00601 = 1.0 -ULES00623 = 0.01 -ULES00640 = 1.0 -ULES00643 = 1.05 -ULES00644 = 1.05 -ULES00645 = 970.0 -ULES00704 = 1.0 -ULES00718 = 1.0 -ULES00722 = 10.0 +ULJM05149 = 1.0 +ULUS10073 = 1.0 + +# Disney/Pixar Ratatouille +UCKS45050 = 10.0 ULES00734 = 10.0 ULES00735 = 10.0 ULES00736 = 10.0 @@ -386,254 +574,724 @@ ULES00746 = 10.0 ULES00747 = 10.0 ULES00748 = 10.0 ULES00749 = 10.0 -ULES00757 = 1.0 -ULES00765 = 1.0 -ULES00766 = 0.95 -ULES00772 = 1.0 -ULES00811 = 10.0 +ULUS10247 = 10.0 + +# DJ Max Fever +NPEH00030 = 1.0 +ULUS10403 = 1.0 + +# DJ Max Portable 2 +ULKS46116 = 1.0 + +# DJ Max Portable 3 +NPJH50471 = 1.0 +ULKS46236 = 1.0 +ULJM05836 = 1.0 +ULJM06033 = 1.0 +ULUS10538 = 1.0 + +# DJ Max Portable: Black Square +NPJH50559 = 1.0 +ULJM06034 = 1.0 +ULKS46189 = 1.0 + +# DJ Max Portable: Clazziquai Edition +ULKS46190 = 1.0 +ULKS46191 = 1.0 + +# DJ Max Portable Hot Tunes +ULKS46240 = 1.0 + +# DreamWorks Shrek the Third +ULES00812 = 0.5 ULES00813 = 0.5 -ULES00841 = 100.0 +ULKS46141 = 0.5 +ULUS10248 = 0.5 + +# Dynasty Warriors +NPJH50030 = 0.1 +ULES00026 = 0.1 +ULES00118 = 0.1 +ULES00119 = 0.1 +ULJM05003 = 0.1 +ULJM08008 = 0.1 +ULJM08017 = 0.1 +ULKS46012 = 0.1 +ULUS10004 = 0.1 + +# Eragon +ULES00474 = 0.1 +ULES00475 = 0.1 +ULUS10146 = 0.1 + +# Evangelion Shin Gekijoban: 3nd Impact +ULAS42293 = 1.0 +ULJS00408 = 1.0 +NPJH50457 = 1.0 + +# F1 Grand Prix +UCAS40026 = 0.1 +UCES00004 = 0.1 +UCJS10019 = 0.1 + +# Family Guy +ULES00567 = 1.0 +ULES00601 = 1.0 +ULUS10185 = 1.0 + +# Fat Princess: Fistful of Cake +NPHG00025 = 80.0 +NPJG00045 = 80.0 +UCAS40285 = 80.0 +UCES01312 = 80.0 +UCKS45137 = 80.0 +UCUS98740 = 80.0 + +# Final Fantasy I +NPJH50406 = 6.8 +UCAS40146 = 6.8 +UCKS45056 = 6.8 +ULES00986 = 6.8 +ULJM05241 = 6.8 +ULJM05514 = 6.8 +ULUS10251 = 6.8 + +# Final Fantasy II +NPJH50407 = 1.0 +UCAS40152 = 1.0 +ULJM05245 = 1.0 +ULJM05515 = 1.0 +ULES00987 = 1.0 +ULUS10263 = 1.0 + +# Final Fantasy III +NPEH00134 = 8.0 +NPHH00351 = 8.0 +NPJH50626 = 8.0 +NPUH10125 = 8.0 +ULJM06133 = 8.0 + +# Final Fantasy IV +NPJH50414 = 1.0 +UCAS40334 = 1.0 +UCAS40342 = 1.0 +ULES01521 = 1.0 +ULJM05855 = 1.0 +ULJM06122 = 1.0 +ULUS10560 = 1.0 + +# Final Fantasy Tactics: The War of the Lions +NPJH50408 = 1.0 +UCAS40148 = 1.0 ULES00850 = 1.0 +ULJM05194 = 1.0 +ULJM05516 = 1.0 +ULUS10297 = 1.0 + +# Final Fantasy Type-0 +NPJH50443 = 100.0 +NPJH50444 = 100.0 +UCAS40346 = 100.0 +ULJM05900 = 100.0 +ULJM06217 = 100.0 + +# flOw +NPEG00003 = 1000.0 +NPJG00004 = 1000.0 +NPUG80086 = 1000.0 + +# Free Running +ULES00704 = 1.0 + +# Ghost in the Shell: Stand Alone Complex +UCAS40025 = 83.0 +UCJS10018 = 83.0 +ULES00135 = 83.0 +ULES00153 = 83.0 +ULUS10020 = 83.0 + +# Ghostbusters: The Video Game +UCES01276 = 3.28 +ULUS10485 = 3.28 +ULUS10486 = 3.28 + +# Gitaroo Man Lives! +NPJH50035 = 50.0 +ULES00383 = 50.0 +ULJM05130 = 50.0 +ULKS46071 = 50.0 +ULUS10207 = 50.0 + +# Gods Eater Burst +NPJH50352 = 100.0 +ULES01519 = 100.0 +ULJS00350 = 100.0 +ULJS00351 = 100.0 +ULJS19056 = 100.0 +ULJS19081 = 100.0 +ULKS46263 = 100.0 +ULUS10563 = 100.0 + +# God of War: Ghost of Sparta +NPEG00044 = 1.0 +NPHG00092 = 1.0 +NPJG00120 = 1.0 +UCAS40323 = 1.0 +UCES01401 = 1.0 +UCES01473 = 1.0 +UCJS10114 = 1.0 +UCKS45161 = 1.0 +UCUS98737 = 1.0 + +# God of War: Chains of Olympus +NPEG00023 = 1.0 +NPUG80325 = 1.0 +UCAS40191 = 1.0 +UCAS40198 = 1.0 +UCED00970 = 1.0 +UCED00971 = 1.0 +UCES00842 = 1.0 +ULJM05348 = 1.0 +UCKS45084 = 1.0 +UCUS98653 = 1.0 +UCUS98705 = 1.0 +UCUS98713 = 1.0 + +# Gran Turismo: The Real Driving Simulator +NPJG00027 = 1.0 +UCAS40265 = 1.0 +UCES01245 = 1.0 +UCJS10100 = 1.0 +UCUS98632 = 1.0 + +# Grand Theft Auto: Chinatown Wars +NPJH00138 = 1.0 +ULES01347 = 1.0 +ULJM05604 = 1.0 +ULUS10490 = 1.0 + +# Grand Theft Auto: Liberty City Stories +NPJH50825 = 0.5 +ULES00051 = 0.5 +ULES00151 = 0.5 +ULES00181 = 0.5 +ULES00182 = 0.5 +ULJM05255 = 0.5 +ULJM05359 = 0.5 +ULJM05885 = 0.5 +ULUS10041 = 0.5 + +# Grand Theft Auto: Vice City Stories +NPJH50827 = 1.0 +ULES00502 = 1.0 +ULES00503 = 1.0 +ULJM05297 = 1.0 +ULJM05395 = 1.0 +ULJM05884 = 1.0 +ULUS10160 = 1.0 + +# Gun Showdown +ULES00484 = 1.0 +ULUS10158 = 1.0 + +# Gungnir +NPEH00135 = 1.0 +NPJH50397 = 1.0 +ULJM05779 = 1.0 +ULUS10592 = 1.0 + +# Harry Potter and the Goblet of Fire +ULES00210 = 1.0 +ULES00214 = 1.0 +ULES00215 = 1.0 +ULES00216 = 1.0 +ULUS10032 = 1.0 + +# Hatsune Miku: Project Diva +NPJH50494 = 3.6 +UCKS45123 = 3.6 +ULAS42163 = 3.6 +ULJM05472 = 3.6 +ULJM05682 = 3.6 + +# Hatsune Miku: Project Diva 2nd +NPJH50475 = 4.0 +ULJM05681 = 4.0 +ULJM05952 = 4.0 + +# Indiana Jones and the Staff of Kings +ULES00939 = 1.0 +ULUS10316 = 1.0 + +# Iron Man 2 +ULES01422 = 1.000999 +ULUS10497 = 1.000999 + +# James Cameron's Avatar: The Game +NPEH00031 = 1.0 +ULES01357 = 1.0 +ULUS10451 = 1.0 + +# Jeanne d'Arc +NPJG00032 = 7.0 +UCAS40129 = 7.0 +UCJS10048 = 7.0 +UCJS18014 = 7.0 +UCJX90019 = 7.0 +UCKS45033 = 7.0 +UCUS98700 = 7.0 +UCUS98706 = 7.0 +ULAS40129 = 7.0 + +# Kingdom Hearts: Birth by Sleep +UCAS40295 = 1.0 +UCAS40317 = 1.0 +UCAS40326 = 1.0 +UCKS45143 = 1.0 +UCKS45168 = 1.0 +ULES01441 = 1.0 +ULJM05600 = 1.0 +ULJM05775 = 1.0 +ULJM06213 = 1.0 +ULJM06214 = 1.0 +ULUS10505 = 1.0 + +# Kingdom of Paradise 1 +UCAS40018 = 9.0 +UCAS40023 = 9.0 +UCAS40089 = 9.0 +UCES00178 = 9.0 +UCET00247 = 9.0 +UCJM95402 = 9.0 +UCJS10010 = 9.0 +UCKS45011 = 9.0 +UCUS98623 = 9.0 + +# Kingdom of Paradise 2 +UCAS40116 = 9.0 +UCAS40156 = 9.0 +UCJS10047 = 9.0 +UCKS45034 = 9.0 + +# LEGO Batman: The Videogame +NPUH90019 = 1.0 +ULES01151 = 1.0 +ULUS10380 = 1.0 + +# LEGO Indiana Jones 1: The Original Adventures +ULES01086 = 47.0 +ULUS10365 = 47.0 + +# LEGO Indiana Jones 2: The Adventure Continues +ULES01370 = 47.0 +ULUS10487 = 47.0 + +# LEGO Star Wars II: The Original Trilogy +ULES00479 = 1.0 +ULUS10155 = 1.0 + +# LEGO Star Wars III: The Clone Wars +ULES01446 = 3.0 +ULUS10531 = 3.0 + +# Lemmings +NPJG00058 = 5.0 +UCAS40076 = 5.0 +UCES00109 = 5.0 +UCET00179 = 5.0 +UCJS10028 = 5.0 +UCUS98647 = 5.0 +UCUS98671 = 5.0 + +# LocoRoco +NPJG00057 = 1.0 +UCAS40063 = 1.0 +UCAS40157 = 1.0 +UCED90007 = 1.0 +UCES00304 = 1.0 +UCET00357 = 1.0 +UCJB98011 = 1.0 +UCJS10041 = 1.0 +UCJS18041 = 1.0 +UCKS45020 = 1.0 +UCKS45055 = 1.0 +UCUS98662 = 1.0 + +# Macross Ace Frontier +ULJS00158 = 1.0 +ULJS19029 = 1.0 + +# Me & My Katamari +NPJH50141 = 1.0 +UCAS40049 = 1.0 +UCKS45022 = 1.0 +ULAS40155 = 1.0 +ULES00339 = 1.0 +ULJS00033 = 1.0 +ULJS19009 = 1.0 +ULUS10094 = 1.0 + +# Mega Man Powered Up +NPJH50183 = 10.0 +UCAS40208 = 10.0 +ULAS42050 = 10.0 +ULAS42052 = 10.0 +ULES00307 = 10.0 +ULJM05044 = 10.0 +ULJM05391 = 10.0 +ULUS10091 = 10.0 + +# Metal Gear Acid 1 +ULAS42007 = 1000.0 +ULES00008 = 1000.0 +ULJM05001 = 1000.0 +ULJM08001 = 1000.0 +ULUS10006 = 1000.0 + +# Metal Gear Acid 2 +ULAS42035 = 930.0 +ULES00284 = 930.0 +ULJM05047 = 930.0 +ULJM08011 = 930.0 +ULKS46065 = 930.0 +ULUS10077 = 930.0 + +# Metal Gear Solid: Digital Graphic Novel +NPJH50128 = 1.0 +ULES00382 = 1.0 +ULJM05150 = 1.0 +ULUS10108 = 1.0 + +# Metal Gear Solid: Peace Walker +NPEH90023 = 1000.0 +NPJH50045 = 1000.0 +ULES01372 = 1000.0 +ULJM05630 = 1000.0 +ULJM08038 = 1000.0 +ULKS46239 = 1000.0 +ULUS10509 = 1000.0 + +# Metal Gear Solid: Portable Ops +NPJH50112 = 970.0 +ULAS42087 = 970.0 +ULES00645 = 970.0 +ULJM05193 = 970.0 +ULJM05227 = 970.0 +ULJM05256 = 970.0 +ULJM05284 = 970.0 +ULJM05573 = 970.0 +ULJM08016 = 970.0 +ULKS46119 = 970.0 +ULUS10202 = 970.0 + +# Monopoly +NPEZ00118 = 70.0 +NPUZ00033 = 70.0 + +# Monster Hunter Freedom 2 +ULAS42110 = 100.0 ULES00851 = 100.0 +ULJM05156 = 100.0 +ULKS46152 = 100.0 +ULUS10266 = 100.0 + +# Monster Hunter Freedom Unite +NPEH90011 = 100.0 +NPJH50244 = 100.0 +ULAS42093 = 100.0 +ULES01213 = 100.0 +ULJM05500 = 100.0 +ULJM08019 = 100.0 +ULJM08053 = 100.0 +ULKS46177 = 100.0 +ULKS46202 = 100.0 +ULUS10391 = 100.0 +ULUS90003 = 100.0 + +# Monster Hunter Portable 3rd +NPJB40001 = 100.0 +NPJH55800 = 100.0 +ULJM05800 = 100.0 +ULJM08058 = 100.0 + +# Nayuta no Kiseki +NPJH50625 = 1.0 +ULJM06113 = 1.0 +ULJM08069 = 1.0 + +# OutRun 2006: Coast 2 Coast +ULES00262 = 10.0 +ULKS46087 = 10.0 +ULUS10064 = 10.0 + +# Patapon 1 +NPJG00054 = 80.0 +UCAS40193 = 80.0 +UCAS40221 = 80.0 +UCES00995 = 80.0 +UCJS10077 = 80.0 +UCJS18027 = 80.0 +UCJS18042 = 80.0 +UCKS45076 = 80.0 +UCUS98711 = 80.0 +UCUS98717 = 80.0 + +# Patapon 2 +NPJG00010 = 80.0 +NPUG98732 = 80.0 +UCAS40232 = 80.0 +UCAS40239 = 80.0 +UCAS40292 = 80.0 +UCES01177 = 80.0 +UCJS10089 = 80.0 +UCJS18036 = 80.0 +UCJS18053 = 80.0 +UCUS98732 = 80.0 + +# Patapon 3 +NPJG00122 = 100.0 +UCAS40318 = 100.0 +UCES01421 = 100.0 +UCJS10113 = 100.0 +UCJS18048 = 100.0 +UCJS18059 = 100.0 +UCKS45169 = 100.0 +UCUS98751 = 100.0 + +# Petz: Dogz Family +ULUS10463 = 3.28 + +# Prince of Persia Revelations +ULES00223 = 1.0 +ULUS10063 = 1.0 + +# Ratchet & Clank: Size Matters +NPJG00015 = 1.0 +UCAS40145 = 1.0 +UCES00420 = 1.0 +UCJS10052 = 1.0 +UCJS18030 = 1.0 +UCJS18047 = 1.0 +UCKS45048 = 1.0 +UCUS98633 = 1.0 + +# Ridge Racer 2 +NPJH50366 = 1000.0 +UCAS40113 = 1000.0 +UCAS40119 = 1000.0 +UCAS40273 = 1000.0 +UCES00422 = 1000.0 +UCKS45032 = 1000.0 +ULJS00080 = 1000.0 + +# Sega Rally Revo +ULAS42119 = 1.0 +ULES00910 = 1.0 +ULET00919 = 1.0 +ULJM05302 = 1.0 +ULJM05417 = 1.0 +ULUS10311 = 1.0 + +# Shin Megami Tensei: Persona 3 Portable +NPJH50040 = 1.0 +UCAS40288 = 1.0 +UCKS45140 = 1.0 +UCKS45175 = 1.0 +ULES01523 = 1.0 +ULJM05489 = 1.0 +ULJM08044 = 1.0 +ULUS10512 = 1.0 + +# Silent Hill: Origins +NPJH50051 = 1.0 +ULAS42117 = 1.0 ULES00869 = 1.0 -ULES00959 = 1.0 +ULJM05281 = 1.0 +ULKS46161 = 1.0 +ULUS10285 = 1.0 + +# Silent Hill: Shattered Memories +NPJH50148 = 1.0 +ULAS42189 = 1.0 +ULES01352 = 1.0 +ULJM05564 = 1.0 +ULJM05828 = 1.0 +ULUS10450 = 1.0 + +# SoulCalibur: Broken Destiny +NPJH50034 = 1.0 +UCKS45126 = 1.0 +ULES01298 = 1.0 +ULJS00202 = 1.0 +ULJS19055 = 1.0 +ULUS10457 = 1.0 + +# Spectral vs Generation +UCAS40102 = 1.0 +ULES00757 = 1.0 +ULJM05162 = 1.0 +ULJM05599 = 1.0 +ULUS10076 = 1.0 + +# Split/Second +NPJH50371 = 10.0 +ULES01402 = 10.0 +ULJM05812 = 10.0 +ULUS10513 = 10.0 + +# Spot the Differences! +NPEZ00107 = 1.0 +NPEZ00108 = 1.0 +NPUZ00034 = 1.0 + +# Star Soldier +NPJH50261 = 1.0 +ULJM05026 = 1.0 +ULJM05235 = 1.0 + +# Star Trek: Tactical Assault +ULES00623 = 0.01 +ULUS10150 = 0.01 + +# Star Wars: Battlefront II +ULAS42037 = 1.0 +ULES00183 = 1.0 +ULJM05060 = 1.0 +ULUS10053 = 1.0 + +# Star Wars: The Force Unleashed +ULES00981 = 100.0 +ULES00982 = 100.0 +ULKS46143 = 100.0 +ULUS10345 = 100.0 + +# Street Fighter Alpha 3 MAX +ULES00235 = 1.0 +ULJM05082 = 1.0 +ULJM05225 = 1.0 +ULUS10062 = 1.0 + +# Sword Art Online: Infinity Moment +NPJH50701 = 1.0 +ULJS00557 = 1.0 +ULJS00558 = 1.0 + +# Tekken: Dark Resurrection +NPJH50137 = 1000.0 +UCAS40095 = 1000.0 +UCAS40099 = 1000.0 +UCAS40164 = 1000.0 +UCAS40165 = 1000.0 +UCED00448 = 1000.0 +UCES00356 = 1000.0 +UCET00424 = 1000.0 +UCKS45027 = 1000.0 +ULJS00048 = 1000.0 +ULJS19013 = 1000.0 +ULUS10139 = 1000.0 + +# Tekken 6 +NPJH50184 = 1000.0 +NPUH10047 = 1000.0 +ULAS42214 = 1000.0 +ULES01376 = 1000.0 +ULJS00224 = 1000.0 +ULJS19054 = 1000.0 +ULKS46235 = 1000.0 +ULKS46265 = 1000.0 +ULUS10466 = 1000.0 + +# Tenchu: Shadow Assassins +UCAS40247 = 10.0 +ULES01237 = 10.0 +ULJM05425 = 10.0 +ULJM05471 = 10.0 +ULJM08027 = 10.0 +ULUS10419 = 10.0 + +# Tenchu: Time of the Assassins +NPJH50042 = 100.0 +UCAS40020 = 100.0 +UCAS40092 = 100.0 +ULES00277 = 100.0 +ULJS00018 = 100.0 +ULJS19007 = 100.0 + +# The 3rd Birthday +NPJH50361 = 100.0 +UCAS40325 = 100.0 +UCAS40336 = 100.0 +UCKS45163 = 100.0 +ULES01513 = 100.0 +ULJM05798 = 100.0 +ULJM06008 = 100.0 +ULUS10567 = 100.0 + +# The Simpsons Game +ULAS42115 = 1.0 ULES00975 = 1.0 ULES00976 = 1.0 ULES00977 = 1.0 ULES00978 = 1.0 ULES00979 = 1.0 -ULES00981 = 100.0 -ULES00982 = 100.0 -ULES00986 = 6.8 -ULES00987 = 1.0 -ULES01013 = 1.0 -ULES01037 = 1.0 -ULES01044 = 100.0 -ULES01045 = 100.0 -ULES01046 = 100.0 -ULES01047 = 100.0 -ULES01086 = 47.0 -ULES01151 = 1.0 -ULES01213 = 100.0 -ULES01237 = 10.0 -ULES01238 = 1.0 -ULES01239 = 1.0 -ULES01240 = 1.0 -ULES01270 = 1.0 -ULES01298 = 1.0 -ULES01347 = 1.0 -ULES01352 = 1.0 -ULES01357 = 1.0 -ULES01367 = 1.0 -ULES01370 = 47.0 -ULES01372 = 1000.0 -ULES01376 = 1000.0 -ULES01381 = 128.0 -ULES01417 = 9.0 -ULES01422 = 1.000999 -ULES01431 = 0.8 -ULES01441 = 1.0 -ULES01505 = 1.0 -ULES01513 = 100.0 -ULES01519 = 100 -ULES01521 = 1.0 -ULES01523 = 1.0 -ULES01526 = 1.0 -ULET00456 = 1.0 -ULET00919 = 1.0 -ULJM05001 = 1000.0 -ULJM05003 = 0.1 -ULJM05026 = 1.0 -ULJM05036 = 1.0 -ULJM05047 = 930.0 -ULJM05049 = 1.0 -ULJM05060 = 1.0 -ULJM05082 = 1.0 -ULJM05104 = 1.0 -ULJM05105 = 1.0 -ULJM05130 = 50.0 -ULJM05149 = 1.0 -ULJM05150 = 1.0 -ULJM05156 = 100.0 -ULJM05162 = 1.0 -ULJM05176 = 1.0 -ULJM05180 = 256.0 -ULJM05181 = 10.0 -ULJM05193 = 970.0 -ULJM05194 = 1.0 -ULJM05227 = 970.0 -ULJM05228 = 1.0 -ULJM05235 = 1.0 -ULJM05241 = 6.8 -ULJM05243 = 1.0 -ULJM05245 = 1.0 -ULJM05254 = 100.0 -ULJM05255 = 1.0 -ULJM05262 = 1.0 -ULJM05275 = 100.0 -ULJM05280 = 1.0 -ULJM05281 = 1.0 -ULJM05284 = 970.0 -ULJM05287 = 100.0 -ULJM05297 = 1.0 -ULJM05302 = 1.0 -ULJM05319 = 10.0 -ULJM05340 = 1.0 -ULJM05348 = 1.0 -ULJM05369 = 1.0 -ULJM05408 = 32.0 -ULJM05425 = 10.0 -ULJM05471 = 10.0 -ULJM05472 = 3.6 -ULJM05492 = 1.0 -ULJM05550 = 1.0 -ULJM05571 = 1.0 -ULJM05600 = 1.0 -ULJM05604 = 1.0 -ULJM05643 = 128.0 -ULJM05681 = 4.0 -ULJM05775 = 1.0 -ULJM05779 = 1.0 -ULJM05798 = 100.0 -ULJM05836 = 1.0 -ULJM05848 = 1.0 -ULJM05859 = 80 -ULJM06034 = 1.0 -ULJM08001 = 1000.0 -ULJM08011 = 930.0 -ULJM08027 = 10.0 -ULJS00003 = 1.0 -ULJS00018 = 100.0 -ULJS00033 = 1.0 -ULJS00048 = 1000.0 -ULJS00080 = 1000.0 -ULJS00086 = 1.0 -ULJS00158 = 1.0 -ULJS00202 = 1.0 -ULJS00224 = 1000.0 -ULJS00350 = 100 -ULJS19001 = 1.0 -ULJS19007 = 100.0 -ULJS19009 = 1.0 -ULJS19013 = 1000.0 -ULJS19018 = 1.0 -ULKS46003 = 1.0 -ULKS46012 = 0.1 -ULKS46021 = 1.0 -ULKS46023 = 10.0 -ULKS46027 = 1.0 -ULKS46057 = 10.0 -ULKS46065 = 930.0 -ULKS46071 = 50.0 -ULKS46116 = 1.0 -ULKS46119 = 970.0 -ULKS46122 = 32.0 -ULKS46139 = 1.0 -ULKS46142 = 1.0 -ULKS46152 = 100.0 -ULKS46155 = 100.0 -ULKS46189 = 1.0 -ULKS46190 = 1.0 -ULKS46236 = 1.0 -ULKS46240 = 1.0 -ULUS10004 = 0.1 -ULUS10006 = 1000.0 -ULUS10014 = 0.005 -ULUS10017 = 10.0 -ULUS10020 = 83 -ULUS10025 = 1.0 -ULUS10027 = 1.0 -ULUS10032 = 1.0 -ULUS10034 = 1.0 -ULUS10037 = 10.0 -ULUS10041 = 1.0 -ULUS10044 = 1.0 -ULUS10050 = 10.0 -ULUS10053 = 1.0 -ULUS10057 = 1.0 -ULUS10062 = 1.0 -ULUS10063 = 1.0 -ULUS10073 = 1.0 -ULUS10077 = 930.0 -ULUS10083 = 1.0 -ULUS10091 = 10.0 -ULUS10094 = 1.0 -ULUS10105 = 7.8 -ULUS10108 = 1.0 -ULUS10110 = 256.0 -ULUS10128 = 1.0 -ULUS10134 = 1.0 -ULUS10139 = 1000.0 -ULUS10146 = 0.1 -ULUS10150 = 0.01 -ULUS10155 = 47.0 -ULUS10156 = 1.0 -ULUS10158 = 1.0 -ULUS10160 = 1.0 -ULUS10175 = 1.0 -ULUS10176 = 1.0 -ULUS10184 = 1.0 -ULUS10185 = 1.0 -ULUS10186 = 1.0 -ULUS10202 = 970.0 -ULUS10207 = 50.0 -ULUS10218 = 1.05 -ULUS10223 = 10.0 -ULUS10227 = 1.0 -ULUS10238 = 1.0 -ULUS10241 = 0.95 -ULUS10245 = 1.0 -ULUS10247 = 10.0 -ULUS10248 = 0.5 -ULUS10251 = 6.8 -ULUS10263 = 1.0 -ULUS10266 = 100.0 -ULUS10273 = 1.0 -ULUS10277 = 100.0 -ULUS10285 = 1.0 ULUS10295 = 1.0 -ULUS10297 = 1.0 -ULUS10311 = 1.0 -ULUS10316 = 1.0 -ULUS10319 = 10.0 -ULUS10325 = 1.0 -ULUS10335 = 1.0 -ULUS10336 = 100.0 -ULUS10345 = 100.0 -ULUS10363 = 1.0 -ULUS10365 = 47.0 -ULUS10380 = 1.0 -ULUS10391 = 100.0 -ULUS10400 = 1.0 -ULUS10403 = 1.0 -ULUS10405 = 1.0 -ULUS10419 = 10.0 -ULUS10431 = 1.0 -ULUS10437 = 1.0 -ULUS10439 = 1.0 -ULUS10450 = 1.0 -ULUS10451 = 1.0 -ULUS10455 = 1.0 -ULUS10457 = 1.0 -ULUS10463 = 3.28 -ULUS10466 = 1000.0 -ULUS10472 = 128.0 -ULUS10486 = 3.28 -ULUS10487 = 47.0 -ULUS10490 = 1.0 -ULUS10497 = 1.000999 -ULUS10505 = 1.0 -ULUS10509 = 1000.0 -ULUS10512 = 1.0 -ULUS10515 = 9.0 -ULUS10519 = 1.0 -ULUS10521 = 0.8 -ULUS10538 = 1.0 -ULUS10560 = 1.0 -ULUS10563 = 100 -ULUS10566 = 1.0 -ULUS10567 = 100.0 -ULUS10579 = 1.0 -ULUS10592 = 1.0 -ULUS90003 = 100.0 +# The Terminator +NPEZ00140 = 1.0 +NPUZ00056 = 1.0 + +# Tomb Raider: Legend +ULES00283 = 256.0 +ULJM05180 = 256.0 +ULUS10110 = 256.0 + +# Tony Hawk's Underground 2 Remix +ULES00033 = 0.005 +ULES00034 = 0.005 +ULES00035 = 0.005 +ULUS10014 = 0.005 + +# Ultimate Ghosts 'n Goblins +NPJH50235 = 7.8 +ULAS42069 = 7.8 +ULAS42073 = 7.8 +ULES00419 = 7.8 +ULJM05147 = 7.8 +ULUS10105 = 7.8 + +# Valkyria Chronicles II +NPJH50145 = 9.0 +ULES01417 = 9.0 +ULJM05560 = 9.0 +ULJM05807 = 9.0 +ULUS10515 = 9.0 + +# Virtua Tennis: World Tour +ULES00126 = 10.0 +ULJM05079 = 10.0 +ULKS46023 = 10.0 +ULUS10037 = 10.0 + +# Wipeout Pulse +NPEG90003 = 1.0 +NPUG70008 = 1.0 +UCAS40179 = 1.0 +UCES00465 = 1.0 +UCET00713 = 1.0 +UCKS45078 = 1.0 +UCUS98712 = 1.0 + +# Wipeout Pure +NPJG00059 = 1.0 +UCAS40012 = 1.0 +UCES00001 = 1.0 +ULJM05105 = 1.0 +UCJS10007 = 1.0 +UCKS45008 = 1.0 +UCUS98612 = 1.0 + +# WWE SmackDown! vs. Raw 2006 +ULES00227 = 10.0 +ULJM05103 = 10.0 +ULKS46057 = 10.0 +ULUS10050 = 10.0 diff --git a/assets/flash0/font/jpn0.pgf b/assets/flash0/font/jpn0.pgf index e0fba76219..7e191ef62c 100644 Binary files a/assets/flash0/font/jpn0.pgf and b/assets/flash0/font/jpn0.pgf differ diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 20d525747b..f5ef62b556 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -137,7 +137,6 @@ Backend = ‎&خلفية التصيير(إعادة تشغيل PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = ‎&تصيير مخفف Buy Gold = ‎إشتري النسخة الإحترافية & Control Mapping... = ‎&تخطيط التحكم... Debugging = ‎&تصحيح @@ -146,7 +145,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = ‎&التفكيك... Discord = Discord -Display Layout Editor = ‎أظهر مُعدل النسق... +Display Layout && Effects = ‎أظهر مُعدل النسق... Display Rotation = ‎تدوير العرض Dump Next Frame to Log = ‎تصحيح الفريم التالي إلي سجل Emulation = ‎&محاكاة @@ -181,7 +180,7 @@ Log Console = ‎&سجل الكونسول Memory View... = ‎عرض الرام... More Settings... = ‎&إعدادات إضافية... Nearest = ‎&الأقرب -Non-Buffered Rendering = ‎&تخطي تأثيرات الصقل (غير مصقول, أسرع) +Skip Buffer Effects = ‎&تخطي تأثيرات الصقل (غير مصقول, أسرع) Off = ‎&مغلق Open Chat = Open Chat Open Directory... = ‎إفتح مسار&... @@ -193,7 +192,6 @@ Pause = ‎&إيقاف مؤقت Pause When Not Focused = ‎&إيقاف مؤقت حينما لا يكون مفعلاً Portrait = ‎لوحة Portrait reversed = ‎لوحة معكوسة -Postprocessing Shader = Postprocessin&g shader PPSSPP Forums = ‎PPSSPP &منتديات Record = ‎&تسجيل Record Audio = ‎تسجيل &الصوت @@ -241,7 +239,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = ‎تفعيل سجل التصحيح Enter address = ‎أدخل العنوان @@ -249,12 +247,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = ‎اللغة -Load language ini = ‎تحميل ملف اللغة Log Dropped Frame Statistics = ‎سجل التفاصيل للفريمات المتدنية Log Level = ‎مستوي السجل Log View = ‎أظهر السجل @@ -270,7 +266,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = ‎شغل فحوص المعالج -Save language ini = ‎إحفظ ملف اللغة Save new textures = ‎حفظ الرسم الجديد Shader Viewer = ‎مستعرض الرسوميات Show Developer Menu = ‎أظهر قائمة المطور @@ -326,6 +321,8 @@ Load completed = ‎التحميل إكتمل. Loading = ‎تحميل\nمن فضلك إنتظر... LoadingFailed = ‎غير قادر علي تحميل البيانات. Move = ‎تحريك +Move Down = Move Down +Move Up = Move Up Network Connection = ‎إتصال الشبكة NEW DATA = ‎بيانات جديدة No = ‎لا @@ -333,6 +330,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = ‎حسناً Old savedata detected = ‎بيانات حفظ قديمة قد إكتشفت Options = ‎إعدادات +Remove = Remove Reset = ‎إستعادة Resize = ‎تغيير الحجم Retry = ‎حاول مجدداً @@ -468,6 +466,8 @@ Aggressive = ‎عنيف Alternative Speed = سرعة ثانوية (في %, 0 = ‎غير محدود) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ‎فلتر الحواف +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = ‎تلقائي Auto (1:1) = ‎تلقائي (1:1) Auto (same as Rendering) = ‎تلقائي (مثل حجم التصيير) @@ -477,11 +477,8 @@ Auto Scaling = ‎تكبير تلقائي Backend = ‎الخلفي Balanced = ‎متناسق Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = ‎الأثنين Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = ‎التصيير المُخفف BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -499,16 +496,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = ‎أظهر مُعدل النسق Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = ‎التحكم في معدل الإطارات Frame Skipping = ‎تخطي الإطارات Frame Skipping Type = Frame skipping type FullScreen = ‎الشاشة الكاملة -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware transform @@ -533,7 +530,7 @@ Must Restart = ‎يجب عليك إعادة تشغيل البرنامج لكي Native device resolution = ‎حجم الجهاز الأساسي Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = ‎لا شئ Number of Frames = Number of frames Off = ‎مغلق @@ -542,28 +539,27 @@ Overlay Information = ‎معلومات النسق Partial Stretch = ‎تمطيط جزئي Percent of FPS = Percent of FPS Performance = ‎الأداء -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = ‎وضع التصيير Rendering Resolution = ‎حجم التصيير RenderingMode NonBuffered Tip = ‎أسرع, لكن يمكن أن لا يظهر أي شئ في بعض الألعاب -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = ‎يجعل ألعاب كثيرة بطيئة, لكن بعض الألعاب أسرع Rotation = ‎الدوران Safe = ‎أمن -Screen layout = Screen layout Screen Scaling Filter = ‎فلتر تكبير حجم الشاشة Show Debug Statistics = ‎أظهر معلومات التصحيح Show FPS Counter = ‎أظهر عداد الـFPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ‎تصيير السوفت وير (slow) Software Skinning = ‎طلاء برمجي SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = ‎السرعة -Stretching = ‎المط +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = ‎المط Texture Filter = ‎منقي الرسوم Texture Filtering = ‎مفلتر الرسوم Texture Scaling = ‎تكبير الرسوم @@ -836,9 +832,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = ‎AA-لون Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -848,22 +844,25 @@ Brightness = Brightness Cartoon = ‎كرتوني CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = ‎CRT خطوط الفحص FXAA = ‎FXAA منعم الحواف Gamma = Gamma -Grayscale = ‎التدرج الرمادي +GreenLevel = Green level Intensity = Intensity -InverseColors = ‎عكس الألوان +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = ‎الألوان الحقيقية NaturalA = Natural Colors (no blur) Off = ‎مغلق Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = ‎تنعيم الحواف +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1033,8 +1032,10 @@ Size = ‎الحجم Uninstall = ‎إلغاء التثبيت [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1052,6 +1053,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1107,6 +1109,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = ‎اللغة Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = ‎تغيير الأسم المستعار @@ -1228,3 +1232,17 @@ Details = Details Dismiss = ‎إلغاء Download = ‎تحميل New version of PPSSPP available = ‎تتوفر نسخة جديدة من البرنامج + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 26b022eb25..490862373a 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Dil faylı yüklə(.ini) Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Dil faylını qeyd et (.ini) Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = Yükləmə Tamamlandı Loading = Yüklənir\nZəhmət Olmasa Gözləyin... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = Xeyir @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Yükləyərək Aç BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control Frame Skipping = Kvadrat Keçid et (Sürət) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Təchizat Dönüşüm @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = None Number of Frames = Number of frames Off = Off @@ -534,28 +531,27 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (experimental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering Texture Scaling = Texture scaling @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Change nickname @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 1c2ba43a4e..945fd274a4 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Купи &Gold Control Mapping... = Контроли... Debugging = &Debug @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Емулация @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Памет изглед... More Settings... = Още настройки... Nearest = &Най-близко -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Изключено Open Chat = Open Chat Open Directory... = Отвори директория... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = Пауза, когато не фокусиран Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &форум Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Език -Load language ini = Зареди езиков ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Сигурни ли сте, че искате да въ RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Запази езиков ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Покажи developer меню @@ -318,6 +313,8 @@ Load completed = Зареждането завършено. Loading = Зареждане\nМоля изчакайте... LoadingFailed = Unable to load data. Move = Преместване +Move Down = Move Down +Move Up = Move Up Network Connection = Мрежова връзка NEW DATA = Нови данни No = Не @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Преоразмеряване Retry = Нов опит @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Алтернативна скорост Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic филтриране +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Автоматично Auto (1:1) = Автоматично (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = И двете Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = Кадри в сек. Frame Rate Control = Framerate control Frame Skipping = Прескачане на кадри Frame Skipping Type = Frame skipping type FullScreen = Цял екран -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware Transform @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Най-близко No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Нищо Number of Frames = Number of frames Off = Изключен @@ -534,28 +531,27 @@ Overlay Information = Обща информация Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Покажи debug инфо Show FPS Counter = Покажи брояча за кадри в сек. -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (експериментално) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Скорост -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Текстурно филтриране Texture Filtering = Текстурно филтриране Texture Scaling = Текстурно мащабиране @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Анимация CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Сива скала +GreenLevel = Green level Intensity = Intensity -InverseColors = Противоположни цветове +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Изключено Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Изостряне +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Големина Uninstall = Деинсталирай [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Език Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Промени прякор @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Откажи Download = Свали New version of PPSSPP available = Налична е нова версия на PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 1f823575e8..a14b220e4b 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -129,7 +129,6 @@ Backend = Motor &gràfic (requereix reiniciar) Bicubic = &Bicúbic Break = Break Break on Load = Break on load -Buffered Rendering = &Renderitzat en memòria intermèdia Buy Gold = Compreu la versió &Gold Control Mapping... = Assigneu els &botons... Debugging = &Depuració @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Editeu la posició dels botons... +Display Layout && Effects = Editeu la posició dels botons... Display Rotation = Rotació de la pantalla Dump Next Frame to Log = Aboca el següent marc al registre Emulation = &Emulació @@ -173,7 +172,7 @@ Log Console = Consola de re&gistres Memory View... = Visor de &memòria... More Settings... = Més &paràmetres... Nearest = &El més proper -Non-Buffered Rendering = &Renderitzat sense memòria intermèdia (més ràpid) +Skip Buffer Effects = &Renderitzat sense memòria intermèdia (més ràpid) Off = &No Open Chat = Open Chat Open Directory... = Obriu &directori... @@ -185,7 +184,6 @@ Pause = &Pausa Pause When Not Focused = &Pausa quan es canviï de finestra Portrait = Vertical Portrait reversed = Vertical invertit -Postprocessing Shader = &Shader de postprocessat PPSSPP Forums = &Fòrums de PPSSPP Record = Enregistreu Record Audio = Enregistreu Àudio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Aboca «EBOOT.BIN» desxifrat quan s'iniciï el joc -Dump Frame GPU Commands = Aboca ordres del marc GPU +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Activa el registre Enter address = Inseriu adreça @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Amideu el rendiment GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Comparació Jit JIT debug tools = JIT debug tools -Language = Llengua -Load language ini = Carrega INI d'idioma Log Dropped Frame Statistics = Registra estadístiques de caigudes de marcs Log Level = Nivell del registre Log View = Vegeu el registre @@ -262,7 +258,6 @@ RestoreDefaultSettings = Esteu segur que voleu restablir els ajustaments de fàb RestoreGameDefaultSettings = Esteu segur que voleu restablir els paràmetres de joc\na els paràmetres per defecte de PPSSPP? Resume = Resume Run CPU Tests = Proves de CPU -Save language ini = Desa l'INI de l'idioma Save new textures = Desa les noves textures Shader Viewer = Visualitzador de shader Show Developer Menu = Mostra el menú de desenvolupament @@ -318,6 +313,8 @@ Load completed = Carrega completada Loading = Carregant\nEspera un moment... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = No @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtrat anisotròpic +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicúbic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Renderizat per buffer BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control Frame Skipping = Saltar fotogrames (skip) Frame Skipping Type = Frame skipping type FullScreen = Fullscreen -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Transformació per maquinari @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = None Number of Frames = Number of frames Off = Off @@ -534,28 +531,27 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (experimental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering Texture Scaling = Texture scaling @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Llengua Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Change nickname @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 6682c46ee5..2520baa821 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -129,7 +129,6 @@ Backend = V&ykreslovací Jádro (Restartuje PPSSPP) Bicubic = &Bikubická Break = Break Break on Load = Break on load -Buffered Rendering = Vykreslování &s vyrovnávací pamětí Buy Gold = &Koupit zlaté PPSSPP Control Mapping... = &Mapování ovládání... Debugging = &Ladění @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = R&ozebrání strojového kódu... Discord = Discord -Display Layout Editor = Zobrazit editor rozvržení... +Display Layout && Effects = Zobrazit editor rozvržení... Display Rotation = Otočení obrazovky Dump Next Frame to Log = &Vypsat příští snímek do záznamu Emulation = &Emulace @@ -173,7 +172,7 @@ Log Console = &Konzole záznamu Memory View... = &Zobrazení paměti... More Settings... = D&alší nastavení... Nearest = &Nejbližší -Non-Buffered Rendering = &Přeskočit efekty vyrovnávací paměti (rychlejší, neukládá se do paměti) +Skip Buffer Effects = &Přeskočit efekty vyrovnávací paměti Off = &Vypnuto Open Chat = Open Chat Open Directory... = &Otevřít adresář... @@ -185,7 +184,6 @@ Pause = &Pozastavit Pause When Not Focused = &Pozastavit pokud okno není zaměřeno Portrait = Na výšku Portrait reversed = Na výšku obráceně -Postprocessing Shader = &Shader následného zpracování PPSSPP Forums = &Fóra PPSSPP Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Vypsat dešifrovaný EBOOT.BIN při načtení hry -Dump Frame GPU Commands = Vypsat příkazy snímku pro grafický procesor +Dump next frame to log = Vypsat příští snímek do záznamu Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Povolit záznam při ladění Enter address = Zadejte adresu @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profilovač snímku GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Porovnání JIT JIT debug tools = JIT debug tools -Language = Jazyk -Load language ini = Načíst ini s jazykem Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Úroveň záznamu Log View = Zobrazení záznamu @@ -262,7 +258,6 @@ RestoreDefaultSettings = Jste si jisti obnovou všech nastavení zpět na jejich RestoreGameDefaultSettings = Jste si jisti obnovou nastavení hry\nzpět na výchozí hodnoty PPSSPP? Resume = Resume Run CPU Tests = Spustit zkoušky CPU -Save language ini = Uložit ini s jazykem Save new textures = Save new textures Shader Viewer = Prohlížeč shaderů Show Developer Menu = Zobrazit nabídku pro vývojáře @@ -318,6 +313,8 @@ Load completed = Načítání dokončeno. Loading = Načítání\nČekejte prosím... LoadingFailed = Nelze načíst data. Move = Přesunout +Move Down = Move Down +Move Up = Move Up Network Connection = Síťové připojení NEW DATA = NOVÁ DATA No = Ne @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Zjištěna stará uložená data Options = Volby +Remove = Remove Reset = Resetovat Resize = Velikost Retry = Zkusit znovu @@ -460,6 +458,8 @@ Aggressive = Agresivní Alternative Speed = Alternativní rychlost (v %, 0 = neomezeno) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anizotropní filtrování +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automaticky Auto (1:1) = Automatické (1:1) Auto (same as Rendering) = Automaticky (stejné jako rozlišení vykreslování) @@ -469,11 +469,8 @@ Auto Scaling = Automatické zvětšení Backend = Jádro Balanced = Vyrovnané Bicubic = Bikubická -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Obojí Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Vykreslování s vyrovnávací pamětí BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Zobrazit editor rozvržení +Display Layout && Effects = Zobrazit editor rozvržení Display Resolution (HW scaler) = Rozlišení obrazovky (Hardwarové zvětšení) -Dump next frame to log = Vypsat příští snímek do záznamu Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Kontrola frekvence snímků Frame Skipping = Přeskakování snímků Frame Skipping Type = Frame skipping type FullScreen = Režim celé obrazovky -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Nastavení hacků (Mohou způsobit problémy) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardwarová transformace @@ -525,7 +522,7 @@ Must Restart = Aby došlo k použití těchto změn, je nutné PPSSPP restartova Native device resolution = Původní rozlišení zařízení Nearest = Nejbližší No buffer = No buffer -Non-Buffered Rendering = Přeskočit efekty vyrovnávací paměti (rychlejší, neukládá se do paměti) +Skip Buffer Effects = Přeskočit efekty vyrovnávací paměti None = Nezobrazovat Number of Frames = Number of frames Off = Vypnuto @@ -534,28 +531,27 @@ Overlay Information = Informace v překryvu Partial Stretch = Částečné roztažení Percent of FPS = Percent of FPS Performance = Výkon -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Shader následného zpracování +Postprocessing shaders = Shader následného zpracování Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Režim vykreslování Rendering Resolution = Rozlišení vykreslování RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Zachovat změněné textury (někdy pomalejší) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Otočení Safe = Bezpečné -Screen layout = Screen layout Screen Scaling Filter = Filtr změny velikosti obrazovky Show Debug Statistics = Zobrazit statistiky ladění Show FPS Counter = Zobrazit počítadlo -Simulate Block Transfer = Simulovat efekty přesunu bloků +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Softwarové vykreslování (experimentální) Software Skinning = Textury aplikuje software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Rychlost -Stretching = Roztažení +Speed Hacks = Speed Hacks (Mohou způsobit problémy) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Roztažení Texture Filter = Filtr textur Texture Filtering = Filtrování textur Texture Scaling = Změna velikosti textur @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Barva Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Animák CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Skenovací řádky CRT FXAA = Vyhlazování hran FXAA Gamma = Gamma -Grayscale = Stupně šedi +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverzní barvy +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Přirozené barvy NaturalA = Natural Colors (no blur) Off = Vypnuto Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Skenovací řádky (CRT) Sharpen = Zostřit +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Velikost Uninstall = Odinstalovat [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Jazyk Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Změnit přezdívku @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Později Download = Stáhnout New version of PPSSPP available = Je dostupná nová verze PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 406dee1abd..4eba607452 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Genstarter PPSSPP) Bicubic = &Bicubisk Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered rendering Buy Gold = Køb PPSSPP &guld Control Mapping... = &Ændre tasteplaceringen... Debugging = Fe&jlfind @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = G&em næste frame i loggen Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = &Log konsol Memory View... = Hukommelseso&versigt... More Settings... = &Flere indstillinger... Nearest = &Nærmest -Non-Buffered Rendering = &Skip buffer effekter (ikke-bufferet, hurtigere) +Skip Buffer Effects = &Skip buffer effekter Off = &Slukket Open Chat = Open Chat Open Directory... = &Åben katalog... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = P&ause når ikke i fokus Portrait = Portræt Portrait reversed = Omvendt portræt -Postprocessing Shader = Efterbehandlin&gs shader PPSSPP Forums = PPSSPP &forum Record = Optag Record Audio = Optag Lyd @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump dekrypteret EBOOT.BIN ved spil boot -Dump Frame GPU Commands = Drop frame GPU kommandoer +Dump next frame to log = Gem næste frame i loggen Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Aktiver fejlfindingslogning Enter address = Indtast adresse @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit sammenlign JIT debug tools = JIT debug tools -Language = Sprog -Load language ini = Hent sprog ini Log Dropped Frame Statistics = Log Droppede Frames Statistik Log Level = Logniveau Log View = Log visning @@ -262,7 +258,6 @@ RestoreDefaultSettings = Er du sikker på at du vil sætte indstillinger tilbage RestoreGameDefaultSettings = Er du sikker på at du vil nustille de spilspecifikke\nindstillinger tilbage til standard? Resume = Resume Run CPU Tests = Kør CPU test -Save language ini = Gem sprog ini Save new textures = Gem nye textures Shader Viewer = Shader viewer Show Developer Menu = Vis udviklermenu @@ -318,6 +313,8 @@ Load completed = Hentet. Loading = Henter\nVent venligst... LoadingFailed = Ikke muligt at indlæse data. Move = Flyt +Move Down = Move Down +Move Up = Move Up Network Connection = Netværksforbindelse NEW DATA = NY DATA No = Nej @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Gamle savedata fundet Options = Optioner +Remove = Remove Reset = Nulstil Resize = Størrelse Retry = Prøv igen @@ -460,6 +458,8 @@ Aggressive = Aggressiv Alternative Speed = Alternativ hastighed (i %, 0 = ubegrænset) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropisk filtrering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatisk Auto (1:1) = Automatisk (1:1) Auto (same as Rendering) = Automatisk (Samme som renderingsopløsning) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanceret Bicubic = Bicubisk -BlockTransfer Tip = Nogle spil kræver at denne er tændt for korrekt grafik -BlockTransferRequired = Advarsel: Dette spil kræver at simulerede blok overførsel tilstand er tændt. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Bufferet rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Skærmopløsning (HW scaler) -Dump next frame to log = Gem næste frame i loggen Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Frameratekontrol Frame Skipping = Frameskipping Frame Skipping Type = Frame skipping type FullScreen = Fuldskærm -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack indstillinger (kan give fejl) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware transformering @@ -525,7 +522,7 @@ Must Restart = Du må genstarte PPSSPP for at aktivere denne ændring. Native device resolution = Standard enheds opløsning Nearest = Nærmest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effekter (ikke-buffered, hurtigere) +Skip Buffer Effects = Skip buffer effekter None = Ingen Number of Frames = Number of frames Off = Slukket @@ -534,28 +531,27 @@ Overlay Information = Overlay information Partial Stretch = Delvis strukket Percent of FPS = Percent of FPS Performance = Ydelse -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Efterbehandlings shader +Postprocessing shaders = Efterbehandlings-shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering tilstand Rendering Resolution = Render opløsning RenderingMode NonBuffered Tip = Hurtigere, men intet vises i nogle spil -Retain changed textures = Behold ændrede textures (nogle gange langsommere) -RetainChangedTextures Tip = Gør mange spil langsommere, men nogle spil er meget hurtigere Rotation = Rotation Safe = Sikker -Screen layout = Screen layout Screen Scaling Filter = Skærmskaleringsfilter Show Debug Statistics = Vis debugstatistik Show FPS Counter = Vis FPS -Simulate Block Transfer = Simuler blokoverførsel effekter +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (eksperiment) Software Skinning = Software skinning SoftwareSkinning Tip = Kombiner begrænset model tegning af CPU, hurtigere i fleste spil Speed = Hastighed -Stretching = Stretching +Speed Hacks = Speed Hacks (kan give fejl) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Texturfilter Texture Filtering = Texturfiltrering Texture Scaling = Texturskalering @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Tegnefilm CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlinier FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Gråskala +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverterede farver +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturlige farver NaturalA = Natural Colors (no blur) Off = Slukket Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlinier (CRT) Sharpen = Gør skarpere +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Størrelse Uninstall = Afinstaller [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Sprog Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Ændre kaldenavn @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Afvis Download = Download New version of PPSSPP available = Ny version af PPSSPP tilgængelig + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 0903a464a1..2dfc37987a 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -129,7 +129,6 @@ Backend = Grafik-Backend Bicubic = Bikubisch Break = Anhalten Break on Load = Anhalten beim Laden -Buffered Rendering = Gepuffertes Rendern Buy Gold = Goldversion kaufen Control Mapping... = Tastenbelegung ändern... Debugging = Debug @@ -138,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D11 Disassembly = Disassembler... Discord = Discord -Display Layout Editor = Bildschirmlayout Editor... +Display Layout && Effects = Bildschirmlayout Editor... Display Rotation = Bildschirmdrehung Dump Next Frame to Log = Nächsten Frame im Log speichern Emulation = Emulation @@ -173,7 +172,7 @@ Log Console = Logkonsole Memory View... = Speicheransicht... More Settings... = Mehr Einstellungen... Nearest = Nächster Nachbar -Non-Buffered Rendering = Überspringe Puffereffekte (ungepuffert, schneller) +Skip Buffer Effects = Überspringe Puffereffekte Off = Aus Open Chat = Öffne Chat Open Directory... = Öffne Verzeichnis... @@ -185,7 +184,6 @@ Pause = Pause Pause When Not Focused = Pausieren im Hintergrund Portrait = Hochformat Portrait reversed = Hochformat umgedreht -Postprocessing Shader = Nachbearbeitungs-Shader PPSSPP Forums = PPSSPP Forum Record = Aufzeichnung Record Audio = Ton aufzeichnen @@ -233,7 +231,7 @@ DevMenu = Entwicklermenü Disabled JIT functionality = Deaktivierte JIT Funktionalität Draw Frametimes Graph = Zeichne frametimes Graphen Dump Decrypted Eboot = Entschlüsselte EBOOT.BIN abspeichern (falls verschlüsselt) -Dump Frame GPU Commands = GPU Befehle des Frames ausgeben +Dump next frame to log = Nächsten Frame im Log speichern Enable driver bug workarounds = Aktiviere Driver-Fehler workarounds Enable Logging = Aktiviere Logging Enter address = Adresse eingeben @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame Profiler GPU Driver Test = GPU Treibertest -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU Profil Jit Compare = JIT-Vergleich JIT debug tools = JIT Debug Werkzeuge -Language = Sprache -Load language ini = Sprachdatei laden Log Dropped Frame Statistics = Statistik für fehlende Einzelbilder loggen Log Level = Loglevel Log View = Logbuch @@ -262,7 +258,6 @@ RestoreDefaultSettings = Sind Sie sicher, dass Sie alle Standardeinstellungen\n( RestoreGameDefaultSettings = Wollen Sie wirklich die spielspezifischen Einstellungen\nauf die Werkseinstellungen von PPSSPP zurücksetzen? Resume = Resume Run CPU Tests = CPU Test starten -Save language ini = Sprachdatei speichern Save new textures = Speichere neue Texturen Shader Viewer = Shader-Anzeige Show Developer Menu = Zeige Entwicklermenü @@ -318,6 +313,8 @@ Load completed = Laden abgeschlossen Loading = Laden\nBitte warten... LoadingFailed = Daten konnten nicht geladen werden. Move = Bewegen +Move Down = Move Down +Move Up = Move Up Network Connection = Netzwerkverbindung NEW DATA = Neue Daten No = Nein @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Alter Speicherstand entdeckt Options = Optionen +Remove = Remove Reset = Zurücksetzen Resize = Größe ändern Retry = Wiederholen @@ -460,6 +458,8 @@ Aggressive = Aggressiv Alternative Speed = Alternative Geschwindigkeit Alternative Speed 2 = Alternative Geschwindigkeit 2 (in %, 0 = unlimitiert) Anisotropic Filtering = Anisotropischer Filter +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatisch Auto (1:1) = Automatisch (1:1) Auto (same as Rendering) = Automatisch (Renderauflösung) @@ -469,11 +469,8 @@ Auto Scaling = Auto Skalierung Backend = Grafik-Backend Balanced = Ausgeglichen Bicubic = Bikubisch -BlockTransfer Tip = Manche Spiele benötigen dies für eine korrekte Darstellung -BlockTransferRequired = Warnung: Dieses Spiel benötigt "Blockübertragungseffekte simulieren". Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Gepuffertes Rendern BufferedRenderingRequired = Warnung: Bei diesem Spiel muss "Rendering Modus" auf "Gepuffert" gesetzt werden. Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Gerät Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Deaktiviert -Display layout editor = Bildschirmlayout Editor +Display Layout && Effects = Bildschirmlayout Editor Display Resolution (HW scaler) = Bildschirmauflösung (HW Skalierung) -Dump next frame to log = Nächsten Frame im Log speichern Enable Cardboard VR = Cardboard VR aktivieren FPS = FPS Frame Rate Control = Frameratenkontrolle Frame Skipping = Bilder überspringen Frame Skipping Type = Typ für Bilder überspringen FullScreen = Vollbild -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hacks (kann zu Fehlern führen) Hardware Tessellation = Hardware Tessellation Hardware Transform = Hardware Transformierung @@ -525,7 +522,7 @@ Must Restart = Sie müssen PPSSPP neustarten, damit die Änderungen wirksam werd Native device resolution = Native Auflösung Nearest = Nächster Nachbar No buffer = No buffer -Non-Buffered Rendering = Über&springe Puffereffekte (ungepuffert, schneller) +Skip Buffer Effects = Über&springe Puffereffekte None = Keine Number of Frames = Anzahl an Frames Off = Aus @@ -534,28 +531,27 @@ Overlay Information = Eingeblendete Informationen Partial Stretch = Teilweise strecken Percent of FPS = Prozent an FPS Performance = Leistung -Postprocessing effect = Nachbearbeitungs-Effekte -Postprocessing Shader = Nachbearbeitungs-Shader +Postprocessing shaders = Nachbearbeitungs-Shader Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Kann Framerate smoother in Spielen machen, die eine niedrige Framerate haben. Rendering Mode = Rendermodus Rendering Resolution = Renderauflösung RenderingMode NonBuffered Tip = Schneller, aber keine Anzeige in einigen Spielen -Retain changed textures = Veränderte Texturen behalten (manchmal langsamer) -RetainChangedTextures Tip = Macht viele Spiele langsamer, aber einige andere umso schneller Rotation = Drehung Safe = Sicher -Screen layout = Screen layout Screen Scaling Filter = Filter für Bildskalierung Show Debug Statistics = Debugstatistiken anzeigen Show FPS Counter = FPS anzeigen -Simulate Block Transfer = Blockübertragungseffekte simulieren +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software Renderer (experimentell) Software Skinning = Software Skinning SoftwareSkinning Tip = Reduziert Grafikbefehle und schneller in Spielen mit erweiterter Skinning-Technik, in anderen Spielen langsamer Speed = Geschwindigkeit -Stretching = Strecken +Speed Hacks = Speed Hacks (kann zu Fehlern führen) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Strecken Texture Filter = Texturfilter Texture Filtering = Texturfilterung Texture Scaling = Texturskalierung @@ -829,8 +825,8 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4×HqGLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AAColor Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT Scanlines FXAA = FXAA Gamma = Gamma -Grayscale = Graustufen +GreenLevel = Green level Intensity = Intensity -InverseColors = Farben invertieren +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natürliche Farben NaturalA = Natürliche Farben (kein Blur) Off = Aus Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines Sharpen = Schärfen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Größe Uninstall = Deinstallieren [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d pro Kern, %d Kerne) %d bytes = %d Byte +%d Hz = %d Hz (none detected) = (nichts gefunden) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger vorhanden +Depth buffer format = Depth buffer format Device Info = Geräteinfo Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Sprache Memory Stick folder = Memory Stick Ordner Memory Stick size = Memory Stick size Change Nickname = Spitznamen ändern @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Überspringen Download = Herunterladen New version of PPSSPP available = Neue PPSSPP Version verfügbar + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index d0176fe3a9..f83994a38b 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Alli &Gold Control Mapping... = C&ontrol Mapping... Debugging = Debu&g @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = Ca'b&eranni lako log Emulation = &Emulasi @@ -173,7 +172,7 @@ Log Console = &Konsol log Memory View... = Pempakitan &Memory... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Mate Open Chat = Open Chat Open Directory... = Bukka' &Ngenan... @@ -185,7 +184,6 @@ Pause = &Paus Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forumna Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Palakoi log to gambara' undipa Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Padenni Log Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Bahasa -Load language ini = Bukka' filena to bahasa Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Pajalanni tes CPU -Save language ini = Annai filena to bahasa Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = Tibukka'mi. Loading = Dibukka'i\nTajammi... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = DATA baru No = Edda mane @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Okemi mane Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Lassi to leko'napa Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Panyaring Anisotropic +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Ia mesa Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Pa jio duai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Palakoi log to gambara' undipa Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Atoro'i FRna Frame Skipping = Frameskip Frame Skipping Type = Frame skipping type FullScreen = Layar pol -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Sullei Hardware @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = To paling mandoppi' No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Danggo'mo Number of Frames = Number of frames Off = Mate @@ -534,28 +531,27 @@ Overlay Information = Pempakitan Overlay Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Pa marrender i Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Padenni Debugna Show FPS Counter = Padenni FPSna -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Pakeanni Software Tampilkan (dicoba-cobara) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Lassinna -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Panyaring Texture Texture Filtering = Saring i Texture Texture Scaling = Petonggoi Texture @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Bahasa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Sullei Nickname @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index b3389a229b..47ac574420 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -153,7 +153,6 @@ Backend = Rendering &backend (restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol mapping... Debugging = &Debug @@ -162,7 +161,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump next frame to log Emulation = &Emulation @@ -197,7 +196,7 @@ Log Console = &Log console Memory View... = Memory &view... More Settings... = &More settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &directory... @@ -209,7 +208,6 @@ Pause = &Pause Pause When Not Focused = &Pause when not focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g shader PPSSPP Forums = PPSSPP &forums Record = &Record Record Audio = Record &audio @@ -257,7 +255,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -266,11 +264,9 @@ Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test GPU Profile = GPU profile -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler Jit Compare = JIT compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Load language ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -286,7 +282,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Save language ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -342,6 +337,8 @@ Load completed = Load completed. Loading = Loading\nPlease Wait... LoadingFailed = Unable to load data. Move = Move +Move Up = Move Up +Move Down = Move Down Network Connection = Network Connection NEW DATA = NEW DATA No = No @@ -349,6 +346,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -484,6 +482,8 @@ Aggressive = Aggressive Alternative Speed = Alternative speed (in %, 0 = unlimited) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -493,11 +493,9 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Both = Both Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -515,15 +513,15 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control Frame Skipping = Frame skipping Frame Skipping Type = Frame skipping type FullScreen = Fullscreen +Geometry shader culling = Geometry shader culling Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware transform @@ -548,7 +546,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = None Number of Frames = Number of frames Off = Off @@ -557,28 +555,27 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Show debug statistics Show FPS Counter = Show FPS counter -Simulate Block Transfer = Simulate block transfer effects -Software Rendering = Software rendering (slow) +Skip GPU Readbacks = Skip GPU Readbacks +Software Rendering = Software rendering (slow, accurate) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Speed -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering Texture Scaling = Texture scaling @@ -597,7 +594,6 @@ VSync = VSync Vulkan = Vulkan Window Size = Window size xBRZ = xBRZ -GPU log profiler = GPU log profiler [InstallZip] Delete ZIP file = Delete ZIP file @@ -823,9 +819,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Black border = Black border @@ -833,21 +829,24 @@ Bloom = Bloom Brightness = Brightness Cartoon = Cartoon ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1044,6 +1043,8 @@ Uninstall = Uninstall [SysInfo] %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz +%0.2f Hz = %0.2f Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1061,6 +1062,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Information = Display information @@ -1143,6 +1145,7 @@ Fast Memory = Fast memory (unstable) Floating symbols = Floating symbols Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) frames, 0:off = frames, 0 = off +Game crashed = Game crashed Games list settings = Games list settings General = General Grid icon size = Grid icon size @@ -1153,6 +1156,7 @@ Increase size = Increase size Interpreter = Interpreter IO timing method = I/O timing method IR Interpreter = IR interpreter +Language = Language Memory Stick Folder = Memory Stick folder Memory Stick inserted = Memory Stick inserted MHz, 0:default = MHz, 0 = default @@ -1244,4 +1248,18 @@ New version of PPSSPP available = New version of PPSSPP available Choices: = Choices: List: = List: Progress: %1% = Progress: %1% -Screen representation = Screen representation \ No newline at end of file +Screen representation = Screen representation + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index a251e5cbb7..cd74f8837b 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -129,7 +129,6 @@ Backend = Motor &gráfico (requiere reiniciar) Bicubic = &Bicúbico Break = Romper Break on Load = Romper en carga -Buffered Rendering = &Dibujado por búfer Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botones... Debugging = &Depuración @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Editar posición de botones... +Display Layout && Effects = Editar posición de botones... Display Rotation = Rotación de pantalla Dump Next Frame to Log = &Volcar siguiente cuadro a registro Emulation = &Emulación @@ -173,7 +172,7 @@ Log Console = Consola de re&gistros... Memory View... = Visor de &memoria... More Settings... = Más &opciones... Nearest = &Cercano -Non-Buffered Rendering = &Saltar efectos del búfer (rápido) +Skip Buffer Effects = &Saltar efectos del búfer (rápido) Off = &No Open Chat = Abrir ventana de chat Open Directory... = &Abrir carpeta... @@ -185,7 +184,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar al cambiar de ventana Portrait = &Vertical Portrait reversed = Vertical &invertido -Postprocessing Shader = &Shader de postprocesado PPSSPP Forums = &Foro de PPSSPP Record = G&rabar Record Audio = Grabar &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Desactivar funcionalidad JIT Draw Frametimes Graph = Dibujar gráfico de cuadros Dump Decrypted Eboot = Volcar "EBOOT.BIN" descifrado al iniciar el juego -Dump Frame GPU Commands = Volcar comandos GPU del cuadro +Dump next frame to log = Volcar siguiente cuadro al registro Enable driver bug workarounds = Activar arreglos alternativos para fallos de drivers Enable Logging = Activar registro Enter address = Insertar dirección @@ -241,12 +239,10 @@ FPU = FPU Frame Profiler = Medir rendimiento Framedump tests = Tests de volcado de cuadros GPU Driver Test = Test de controlador GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Perfil GPU Jit Compare = Comparación JIT JIT debug tools = Herramientas de depuración JIT -Language = Idioma -Load language ini = Cargar INI de idioma Log Dropped Frame Statistics = Registrar estadísticas de caídas de fotogramas Log Level = Nivel de registro Log View = Ver el registro @@ -262,7 +258,6 @@ RestoreDefaultSettings = ¿Seguro que quieres volver a los ajustes de fábrica?\ RestoreGameDefaultSettings = ¿Seguro que quieres reestablecer los ajustes del juego\na los ajustes por defecto de PPSSPP? Resume = Reanudar Run CPU Tests = Pruebas de CPU -Save language ini = Guardar INI de idioma Save new textures = Guardar texturas nuevas Shader Viewer = Visor de shader Show Developer Menu = Mostrar menú de desarrollo @@ -318,6 +313,8 @@ Load completed = Carga completada. Loading = Cargando\nEspera un momento... LoadingFailed = Los datos del juego no se pudieron cargar. Move = Posición +Move Down = Move Down +Move Up = Move Up Network Connection = Conexión de red NEW DATA = NUEVOS DATOS DE PARTIDA No = No @@ -325,6 +322,7 @@ ObtainingIP = Obteniendo direcciónnn IP.\nPor favor espera... OK = Aceptar Old savedata detected = Se han detectado datos del juego antiguos. Options = Opciones +Remove = Remove Reset = Reiniciar Resize = Tamaño Retry = Reintentar @@ -460,6 +458,8 @@ Aggressive = Agresivo Alternative Speed = Velocidad alternativa (%, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (%, 0 = ilimitada) Anisotropic Filtering = Filtrado anisotrópico +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Automático (igual a la de renderizado) @@ -469,11 +469,8 @@ Auto Scaling = Autoescalado Backend = Motor gráfico Balanced = Equilibrado Bicubic = Bicúbico -BlockTransfer Tip = Algunos juegos necesitan esta opción para evitar errores gráficos. -BlockTransferRequired = AVISO: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos de búfer gráfico (puede generar input lag) -Buffered Rendering = Dibujado por búfer BufferedRenderingRequired = AVISO: este juego requiere modo de renderizado por búfer. Camera = Cámara Camera Device = Dispositivo de cámara @@ -491,16 +488,16 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desactivado -Display layout editor = Editor del área de pantalla +Display Layout && Effects = Editor del área de pantalla Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) -Dump next frame to log = Volcar siguiente cuadro al registro Enable Cardboard VR = Activar Cardboard VR FPS = FPS Frame Rate Control = Control de tasa de cuadros (FPS) Frame Skipping = Saltar cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (causarán errores gráficos) Hardware Tessellation = Teselado por hardware Hardware Transform = Transformación por hardware @@ -525,7 +522,7 @@ Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa del dispositivo Nearest = Pixelado No buffer = Sin búfer -Non-Buffered Rendering = Saltar efectos del búfer +Skip Buffer Effects = Saltar efectos del búfer None = No Number of Frames = Nº de cuadros Off = No @@ -534,28 +531,27 @@ Overlay Information = Información en pantalla Partial Stretch = Estirado parcial Percent of FPS = % de FPS Performance = Rendimiento -Postprocessing effect = Efecto de postprocesado -Postprocessing Shader = Shader de postprocesado +Postprocessing shaders = Shaders de postprocesado Recreate Activity = Recrear actividad Render duplicate frames to 60hz = Renderizar cuadros duplicados a 60Hz RenderDuplicateFrames Tip = Puede hacer la imagen más fluida in juegos con una tasa de cuadros más baja. Rendering Mode = Modo de renderizado Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Rápido, pero no se verá nada en algunos juegos. -Retain changed textures = Mantener texturas cambiadas -RetainChangedTextures Tip = Hace muchos juegos más lentos, pero unos pocos mucho más rápidos. Rotation = Rotación Safe = Seguro -Screen layout = Diseño de pantalla Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efectos "block transfer" +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderizado por software Software Skinning = "Skinning" por software SoftwareSkinning Tip = Reduce la carga de dibujado, rápido en juegos con técnicas de skinning avanzadas, pero lento en otros. Speed = Velocidad -Stretching = Estirar +Speed Hacks = Speed Hacks (causarán errores gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas Texture Scaling = Escalado de texturas @@ -829,8 +825,8 @@ Undo last save = Deshacer guard. de estado [PostShaders] (duplicated setting, previous slider will be used) = (configuración duplicada, se usará la anterior) 4xHqGLSL = 4xHQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA + color Amount = Cantidad Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brillo Cartoon = Dibujos animados CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Corrección de color +ColorPreservation = Color preservation Contrast = Contraste CRT = Pantalla de tubo (CRT) FXAA = Antialiasing por FXAA Gamma = Gamma -Grayscale = Escala de grises +GreenLevel = Green level Intensity = Intensidad -InverseColors = Invertir colores +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Colores naturales NaturalA = Colores naturales (sin difuminar) Off = No Power = Poder PSPColor = Paleta de colores PSP +RedBlue = Red/Blue glasses Saturation = Saturación Scanlines = Monitor con "scanlines" Sharpen = Afilado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super muestreo AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (ninguno detectado) 3D API = API 3D ABI = Arquitectura @@ -1044,6 +1045,7 @@ CPU Name = Nombre D3DCompiler Version = Versión del compilador D3D Debug = Desarrollo Debugger Present = Depurador presente +Depth buffer format = Depth buffer format Device Info = Info. del dispositivo Directories = Directorios Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes +Game crashed = Game crashed +Language = Idioma Memory Stick folder = Directorio de Memory Stick Memory Stick size = Cambiar tamaño de Memory Stick (GB) Change Nickname = Cambiar apodo PSP @@ -1220,3 +1224,17 @@ Details = Detalles Dismiss = Cancelar Download = Descargar New version of PPSSPP available = Nueva versión de PPSSPP disponible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 46ad0c39e3..67f3418944 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -129,7 +129,6 @@ Backend = Motor &gráfico (requiere reiniciar) Bicubic = &Bicúbico Break = Romper Break on Load = Romper en carga -Buffered Rendering = &Renderizado por búfer Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botones... Debugging = &Depuración @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D 9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Editar posición de botones... +Display Layout && Effects = Editar posición de botones... Display Rotation = Rotación de pantalla Dump Next Frame to Log = &Volcar siguiente cuadro a registro Emulation = &Emulación @@ -173,7 +172,7 @@ Log Console = Consola de re&gistros... Memory View... = Visor de &memoria... More Settings... = Más &opciones... Nearest = &Cercano -Non-Buffered Rendering = &Saltar efectos por búfer (rápido) +Skip Buffer Effects = &Saltar efectos por búfer (rápido) Off = &No Open Chat = Abrir ventana de chat Open Directory... = &Abrir carpeta... @@ -185,7 +184,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar al cambiar de ventana Portrait = Retrato Portrait reversed = Retrato inverso -Postprocessing Shader = &Shader de postprocesado PPSSPP Forums = &Foro de PPSSPP Record = G&rabar Record Audio = Grabar &audio @@ -233,7 +231,7 @@ DevMenu = Menú Depuración Disabled JIT functionality = Apagar funcionalidad de JIT Draw Frametimes Graph = Mostrar gráfica de tiempos de frames Dump Decrypted Eboot = Volcar EBOOT.BIN descifrado al iniciar el juego -Dump Frame GPU Commands = Volcar comandos GPU del cuadro +Dump next frame to log = Volcar siguiente cuadro al registro Enable driver bug workarounds = Activar arreglos alternativos para fallos de drivers Enable Logging = Activar registro Enter address = Insertar dirección @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Pruebas de volcado de frames Frame Profiler = Perfilado de frame GPU Driver Test = Probar controlador GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Perfil de GPU Jit Compare = Comparar JIT JIT debug tools = Herr. de depuración de JIT -Language = Idioma -Load language ini = Cargar INI de idioma Log Dropped Frame Statistics = Registrar estadísticas de frames caídos Log Level = Nivel de registro Log View = Ver el registro @@ -262,7 +258,6 @@ RestoreDefaultSettings = ¿Seguro que quieres volver a los ajustes de fábrica?\ RestoreGameDefaultSettings = ¿Seguro que quieres reestablecer los ajustes del juego\na los ajustes por defecto de PPSSPP? Resume = Reanudar Run CPU Tests = Ejecutando pruebas de CPU -Save language ini = Guardar INI de idioma Save new textures = Guardar nuevas texturas Shader Viewer = Visor de shader Show Developer Menu = Mostrar menú de desarrollador @@ -318,6 +313,8 @@ Load completed = Datos cargados. Loading = Cargando\nPor favor espere... LoadingFailed = Los datos del juego no se pudieron cargar. Move = Mover +Move Down = Move Down +Move Up = Move Up Network Connection = Conexión de red NEW DATA = CREAR DATOS No = No @@ -325,6 +322,7 @@ ObtainingIP = Obteniendo dirección IP.\nEspera un momento... OK = OK Old savedata detected = Se han detectado datos del juego antiguos. Options = Opciones +Remove = Remove Reset = Reiniciar Resize = Tamaño Retry = Reintentar @@ -460,6 +458,8 @@ Aggressive = Agresivo Alternative Speed = Velocidad alternativa (en %, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (en %, 0 = ilimitada) Anisotropic Filtering = Filtrado Anisotrópico +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Automático (igual a la de renderizado) @@ -469,11 +469,8 @@ Auto Scaling = Escalado automático Backend = Motor gráfico Balanced = Balanceado Bicubic = Bicúbico -BlockTransfer Tip = Algunos juegos requieren activarlo para corregir gráficos. -BlockTransferRequired = Advertencia: Este juego requiere activar los efectos de transferencia de bloque. Both = Ambos Buffer graphics commands (faster, input lag) = Comandos gráficos de búfer (puede generar input lag) -Buffered Rendering = Renderizado con Buffer BufferedRenderingRequired = Advertencia: Este juego requiere modo de renderizado por búfer. Camera = Cámara Camera Device = Dispositivo de cámara @@ -491,16 +488,16 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Apagado -Display layout editor = Editor del área de pantalla +Display Layout && Effects = Editor del área de pantalla Display Resolution (HW scaler) = Resolución de pantalla (escalado por HW) -Dump next frame to log = Volcar siguiente cuadro al registro Enable Cardboard VR = Activar Cardboard VR FPS = FPS Frame Rate Control = Control de Framerate Frame Skipping = Salto de cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ajustes de hacks (puede causar glitches) Hardware Tessellation = Teselado por Hardware Hardware Transform = Transformación por Hardware @@ -525,7 +522,7 @@ Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa del dispositivo Nearest = Pixelado No buffer = No hay búfer -Non-Buffered Rendering = Saltar efectos por búfer (Desactiva búfer, rápido) +Skip Buffer Effects = Saltar efectos por búfer (Desactiva búfer, rápido) None = No Number of Frames = Número de Frames Off = Apagado @@ -534,28 +531,27 @@ Overlay Information = Información en pantalla Partial Stretch = Estirado parcial Percent of FPS = % de FPS Performance = Rendimiento -Postprocessing effect = Efectos de postprocesado -Postprocessing Shader = Shader de postprocesado +Postprocessing shaders = Shaders de postprocesado Recreate Activity = Recrear actividad Render duplicate frames to 60hz = Procesar cuadros duplicados a 60 Hz RenderDuplicateFrames Tip = Puede hacer que la fluidez sea más suave en juegos con tasas de cuadros bajas. Rendering Mode = Modo de renderizado Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Acelera, pero no podrá generar gráficos en algunos juegos. -Retain changed textures = Mantener texturas cambiadas -RetainChangedTextures Tip = Ralentiza muchos juegos, pero acelera algunos. Rotation = Rotación Safe = Seguro -Screen layout = Disposición de pantalla Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efectos de transferencia de bloque +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderizado por software (experimental) Software Skinning = Skineado por software SoftwareSkinning Tip = Combina dibujados de modelo de skineado en la CPU. Acelera muchos juegos pero ralentiza otros. Speed = Velocidad -Stretching = Estirar +Speed Hacks = Speed Hacks (puede causar glitches) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Estirar Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas Texture Scaling = Escalado de texturas @@ -828,7 +824,7 @@ Undo last save = Deshacer guard. de estado [PostShaders] (duplicated setting, previous slider will be used) = (configuraciones duplicadas, se usará la anterior) -4xHqGLSL = 4×HQ GLSL +4xHqGLSL = 4xHQ pixel art upscaler 5xBR = 5×BR 5xBR-lv2 = 5×BR-lv2 AAColor = AA + Color @@ -840,22 +836,25 @@ Brightness = Brillo Cartoon = Caricaturas CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Corrección de color +ColorPreservation = Color preservation Contrast = Contraste CRT = Pantalla de tubo (CRT) FXAA = Antialiasing por FXAA Gamma = Gamma -Grayscale = Escala de grises +GreenLevel = Green level Intensity = Intensidad -InverseColors = Invertir colores +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Colores naturales NaturalA = Colores naturales (sin desenfoques) Off = Apagado Power = Power PSPColor = Paleta de colores PSP +RedBlue = Red/Blue glasses Saturation = Saturación Scanlines = Líneas de escaneo (CRT) Sharpen = Afilado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super muestreo AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (No se ha detectado) 3D API = API 3D ABI = Arquitectura @@ -1044,6 +1045,7 @@ CPU Name = Nombre D3DCompiler Version = Versión del compilador D3D Debug = Desarrollo Debugger Present = Depurador presente +Depth buffer format = Depth buffer format Device Info = Info de dispositivo Directories = Directorios Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes +Game crashed = Game crashed +Language = Idioma Memory Stick folder = Carpeta del Memory Stick Memory Stick size = Tamaño del Memory Stick Change Nickname = Cambiar nombre de usuario @@ -1220,3 +1224,17 @@ Details = Detalles Dismiss = Cancelar Download = Descargar New version of PPSSPP available = Nueva versión de PPSSPP disponible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 4ea5d675dc..2779016c4e 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -129,7 +129,6 @@ Backend = ‎Rendering &Backend (ریستارت میشود PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = ‎رندر کردن از بافر Buy Gold = ‎خرید نسخه طلایی Control Mapping... = ‎...تنظیمات کنترلر Debugging = ‎دیباگ @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = ‎...جداسازی قطعات Discord = Discord -Display Layout Editor = ‎ویرایشگر چیدمان صفحه +Display Layout && Effects = ‎ویرایشگر چیدمان صفحه Display Rotation = ‎چرخش صفحه Dump Next Frame to Log = ‎تخلیه فریم بعدی به فایل لاگ Emulation = ‎شبیه سازی @@ -173,7 +172,7 @@ Log Console = ‎کنسول لاگ Memory View... = ‎...نمایش مموری More Settings... = ‎...تنظیمات بیشتر Nearest = ‎نزدیک ترین -Non-Buffered Rendering = ‎رد کردن اثرات بافر (سریع تر) +Skip Buffer Effects = ‎رد کردن اثرات بافر (سریع تر) Off = ‎خاموش Open Chat = Open Chat Open Directory... = ‎... بازکردن مسیر @@ -185,7 +184,6 @@ Pause = ‎مکث Pause When Not Focused = ‎هنگامی که پنجره فعال نباشد بازی متوقف شود Portrait = ‎عمودی Portrait reversed = ‎عمودی وارونه -Postprocessing Shader = ‎اضافه کردن افکت PPSSPP Forums = ‎PPSSPP انجمن های Record = ‎ضبط کردن Record Audio = ‎ضبط صدا @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = ‎ریختن فریم بعدی به فایل لاگ Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = ‎روشن کردن لاگ باگ ها Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = ‎زبان -Load language ini = ‎ini بارگیری فایل زبان با فرمت Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = ‎آیا شما می خواهید که تمامی تن RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = ‎CPU اجرای تست -Save language ini = ‎ini ذخیره فایل زبان با فرمت Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = ‎.بارگیری نکمیل شد Loading = ‎درحال بارگیری\n...منتظر بمانید LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = ‎دیتای جدید No = ‎خیر @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = ‎تایید Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = ‎شدید Alternative Speed = ‎سرعت ثانویه Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ‎Anisotropic فیلتر +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = ‎اتوماتیک Auto (1:1) = Auto (1:1) Auto (same as Rendering) = ‎خودکار (مانند رزولوشن رندرینگ) @@ -469,11 +469,8 @@ Auto Scaling = ‎تنظیم سایز خودکار Backend = ‎گرافیکی API Balanced = ‎متعادل Bicubic = Bicubic -BlockTransfer Tip = ‎در بعضی بازی ها برای نشان دادن درست گرافیک نیاز است -BlockTransferRequired = ‎دارد "simulate block transfer effects" هشدار:این گزینه نیاز به روشن بودن Both = ‎سرعت + فریم بر ثانیه Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = ‎رندر کردن از بافر BufferedRenderingRequired = ‎تنظیم باشد "buffered" هشدار: برای این بازی "حالت رندرینگ" باید روی Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = ‎ویرایشگر چیدمان صفحه +Display Layout && Effects = ‎ویرایشگر چیدمان صفحه Display Resolution (HW scaler) = ‎رزولوشن صفحه -Dump next frame to log = ‎ریختن فریم بعدی به فایل لاگ Enable Cardboard VR = Enable Cardboard VR FPS = ‎فریم بر ثانیه Frame Rate Control = ‎کنترل سرعت فریم Frame Skipping = ‎ردکردن فریم Frame Skipping Type = Frame skipping type FullScreen = ‎تمام صفحه -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ‎تنظیمات هک ها (میتواند باعث باگ شود) Hardware Tessellation = Hardware tessellation Hardware Transform = ‎استفاده از سخت افزار در پردازش @@ -525,7 +522,7 @@ Must Restart = ‎برای اعمال این تنظیم باید برنامه ر Native device resolution = ‎رزولوشن دستگاه Nearest = ‎نزدیک ترین No buffer = No buffer -Non-Buffered Rendering = ‎رد کردن اثر بافر (سریع تر) +Skip Buffer Effects = ‎رد کردن اثر بافر (سریع تر) None = ‎هیچ Number of Frames = Number of frames Off = ‎خاموش @@ -534,28 +531,27 @@ Overlay Information = ‎Overlay اطلاعات Partial Stretch = ‎کشیدگی جزئی Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = ‎افکت پس-پردازش +Postprocessing shaders = ‎افکت پس-پردازش Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = ‎حالت رندرینگ Rendering Resolution = ‎رزولوشن رندرینگ RenderingMode NonBuffered Tip = ‎سریع تر، اما در بعضی بازی ها ممکن است چیزی نشان ندهد -Retain changed textures = ‎کش کردن تکسچر های تغییر یافته (بعضی مواقع کندتر) -RetainChangedTextures Tip = ‎برای بسیاری از بازی ها کندتر و برای بعضی سریع تر Rotation = ‎چرخش Safe = ‎امن -Screen layout = Screen layout Screen Scaling Filter = ‎فیلتر تغییر ساز صفحه Show Debug Statistics = ‎نمایش اطلاعات دیباگ Show FPS Counter = ‎نمایش شمارنده فریم بر ثانیه -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ‎(رندر نرم افزاری (آزمایشی Software Skinning = Software skinning SoftwareSkinning Tip = ‎در اکثر بازی ها سریع تر ،CPU دار در skin ترکیب رسم مدل های Speed = ‎سرعت -Stretching = ‎کشیدن +Speed Hacks = Speed Hacks ‎(میتواند باعث باگ شود) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = ‎کشیدن Texture Filter = ‎فیلتر تکسچر Texture Filtering = ‎فیلتر کردن تکسچر Texture Scaling = ‎تغییر سایز تکسچر ها @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = ‎زبان Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = ‎تغییر نام @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 94dd50c642..3dddf029cc 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ota virheenkorjauksen kirjaaminen käyttöön Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Lataa kielipaketti Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Suorita suoritin testi -Save language ini = Tallenna kielipaketti Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = Lataus onnistui. Loading = Ladataan\nOdota... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = Ei @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Vaihtoehtoinen nopeus Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotrooppisen suodatus +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Molemmat Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Puskuroitu renderointi BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control Frame Skipping = Ruudun ohitus Frame Skipping Type = Frame skipping type FullScreen = Koko näyttö -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Laitteistomuunnos @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Lähin No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Ei mitään Number of Frames = Number of frames Off = Off @@ -534,28 +531,27 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Näytä virheenkorjaustilastot Show FPS Counter = Näytä FPS-laskuri -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Ohjelmistopohjainen renderointi (kokeellinen) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Nopeus -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Tekstuurisuodatin Texture Filtering = Tekstuurin suodatus Texture Scaling = Tekstuurin skaalaus @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Vaihda nimimerkkiä @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 6c28c420e0..9a0db6f84e 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -129,7 +129,6 @@ Backend = Rendu &back-end (redémarre PPSSPP) Bicubic = &Bicubique Break = Arrêter Break on Load = Arrêter au lancement -Buffered Rendering = &Mise en mémoire tampon Buy Gold = Acheter la version &Gold Control Mapping... = R&éassignation des touches... Debugging = &Débogage @@ -138,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = Dés&assembleur Discord = Discord -Display Layout Editor = Éditeur d'affichage... +Display Layout && Effects = Éditeur d'affichage... Display Rotation = Rotation de l'affichage Dump Next Frame to Log = &Dump de l'image suivante dans le journal Emulation = &Émulation @@ -173,7 +172,7 @@ Log Console = &Journal de débogage Memory View... = &Visionneur de mémoire More Settings... = &Plus de paramètres... Nearest = Le plus &proche -Non-Buffered Rendering = &Pas d'effets en mémoire tampon (hack de vitesse) +Skip Buffer Effects = &Pas d'effets en mémoire tampon (hack de vitesse) Off = &Désactivé Open Chat = Open Chat Open Directory... = Ouvrir &répertoire... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = Mettre en pa&use si pas au premier plan Portrait = Portrait Portrait reversed = Portrait inversé -Postprocessing Shader = S&haders de post-traitement PPSSPP Forums = Visiter le &forum de PPSSPP Record = E&nregistrer Record Audio = Enregistrer le &son @@ -233,7 +231,7 @@ DevMenu = MenuDev Disabled JIT functionality = Fonctionnalité JIT désactivée Draw Frametimes Graph = Dessiner le graphique des temps d'image Dump Decrypted Eboot = Créer un EBOOT.BIN déchiffré au lancement du jeu -Dump Frame GPU Commands = Dump des commandes GPU de l'image +Dump next frame to log = Dump de l'image suivante dans le journal Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Activer le journal de débogage Enter address = Entrer une adresse @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profileur d'image GPU Driver Test = Test du pilote du GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Profilage du GPU Jit Compare = Comparaison JIT JIT debug tools = Outils de débogage JIT -Language = Langue -Load language ini = Charger fichier de langue Log Dropped Frame Statistics = Enregistrer les statistiques sur les pertes d'images Log Level = Niveau du journal Log View = Voir le journal @@ -262,7 +258,6 @@ RestoreDefaultSettings = Êtes-vous sûr de vouloir restaurer tous les paramètr RestoreGameDefaultSettings = Êtes-vous sûr de vouloir restaurer tous les paramètres\nspécifiques au jeu à leur valeur par défaut de PPSSPP ? Resume = Reprendre Run CPU Tests = Exécuter des tests CPU -Save language ini = Sauvegarder fichier de langue Save new textures = Sauvegarder les nouvelles textures Shader Viewer = Visionneur de shader Show Developer Menu = Montrer le menu développeur "MenuDev" @@ -318,6 +313,8 @@ Load completed = Chargement terminé. Loading = Chargement\nVeuillez patienter... LoadingFailed = Chargement impossible. Move = Déplacer +Move Down = Move Down +Move Up = Move Up Network Connection = Connexion réseau NEW DATA = NOUVELLES DONNÉES No = Non @@ -325,6 +322,7 @@ ObtainingIP = Obtention de l'adresse IP\nVeuillez patienter... OK = OK Old savedata detected = Ancienne sauvegarde détectée Options = Options +Remove = Remove Reset = Remise à 0 Resize = Zoomer Retry = Réessayer @@ -460,6 +458,8 @@ Aggressive = Agressif Alternative Speed = Vitesse alternative 1 (en %, 0 = illimitée) Alternative Speed 2 = Vitesse alternative 2 (en %, 0 = illimitée) Anisotropic Filtering = Filtrage anisotrope +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatique Auto (1:1) = Automatique (1:1) Auto (same as Rendering) = Automatique (comme la définition du rendu) @@ -469,11 +469,8 @@ Auto Scaling = Mise à l'échelle auto Backend = Rendu back-end Balanced = Équilibré Bicubic = Bicubique -BlockTransfer Tip = Certains jeux requièrent l'activation de ce paramètre pour obtenir des graphismes corrects -BlockTransferRequired = Avertissement : Ce jeu requiert l'activation de "Simuler les effets de transfert de bloc". Both = Vitesse + FPS Buffer graphics commands (faster, input lag) = Commandes graphiques en mémoire tampon (+ rapide, + lag entrée) -Buffered Rendering = Mise en mémoire tampon BufferedRenderingRequired = Avertissement : Ce jeu requiert "mode de rendu" réglé sur "Mise en mémoire tampon". Camera = Caméra Camera Device = Caméra @@ -491,16 +488,16 @@ Device = Appareil Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Désactivé -Display layout editor = Éditeur d'affichage +Display Layout && Effects = Éditeur d'affichage Display Resolution (HW scaler) = Définition d'affichage (mise à l'échelle matérielle) -Dump next frame to log = Dump de l'image suivante dans le journal Enable Cardboard VR = Activer Cardboard VR FPS = FPS Frame Rate Control = Contrôle de la fréquence de rafraîchissement des images Frame Skipping = Saut d'images Frame Skipping Type = Type de saut d'images FullScreen = Plein écran -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Paramètres "hack" (crée des bugs graphiques) Hardware Tessellation = Tessellation matérielle Hardware Transform = Transformation matérielle @@ -525,7 +522,7 @@ Must Restart = Vous devez redémarrer PPSSPP pour que cette modification prenne Native device resolution = Définition native de l'appareil Nearest = Le plus proche No buffer = 0 -Non-Buffered Rendering = Pas d'effets en mémoire tampon (hack vitesse) +Skip Buffer Effects = Pas d'effets en mémoire tampon (hack vitesse) None = Aucun Number of Frames = Nombre d'images Off = Désactivé @@ -534,28 +531,27 @@ Overlay Information = Informations incrustées à l'écran Partial Stretch = Étirement partiel Percent of FPS = Pourcentage de FPS Performance = Performances -Postprocessing effect = Effets de post-traitement -Postprocessing Shader = Shaders de post-traitement +Postprocessing shaders = Shaders de post-traitement Recreate Activity = Recréer l'animation Render duplicate frames to 60hz = Dupliquer les images pour atteindre 60 Hz RenderDuplicateFrames Tip = Peut améliorer la fluidité dans les jeux qui fonctionnent à des fréquences d'images plus faibles Rendering Mode = Mode de rendu Rendering Resolution = Définition du rendu RenderingMode NonBuffered Tip = Plus rapide, mais pour certains jeux rien ne s'affichera -Retain changed textures = Conserver les textures modifiées (seulement certains jeux) -RetainChangedTextures Tip = Ralentit de nombreux jeux, mais beaucoup plus rapide pour quelques autres Rotation = Rotation Safe = Prudent -Screen layout = Disposition de l'écran Screen Scaling Filter = Filtre de mise à l'échelle de l'écran Show Debug Statistics = Montrer les statistiques de débogage Show FPS Counter = Montrer les compteurs -Simulate Block Transfer = Simuler les effets de transfert de bloc +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Rendu logiciel (expérimental) Software Skinning = Enveloppe logicielle SoftwareSkinning Tip = Combine l'affichage des modèles enveloppés sur le CPU, plus rapide dans la plupart des jeux Speed = Vitesse -Stretching = Étirement +Speed Hacks = Speed Hacks (crée des bugs graphiques) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Étirement Texture Filter = Filtre de textures Texture Filtering = Filtrage des textures Texture Scaling = Mise à l'échelle des textures @@ -840,22 +836,25 @@ Brightness = Luminosité Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Correction des couleurs +ColorPreservation = Color preservation Contrast = Contraste CRT = Lignes de balayage CRT FXAA = Anticrénelage FXAA Gamma = Gamma -Grayscale = Niveaux de gris +GreenLevel = Green level Intensity = Intensité -InverseColors = Couleurs inversées +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Couleurs naturelles NaturalA = Couleurs naturelles (sans flou) Off = Aucun Power = Puissance PSPColor = Couleurs PSP +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Lignes de balayage Sharpen = Plus net +SideBySide = Side by side (SBS) SSAA(Gauss) = Anticrénelage supersampling (Gauss) Tex4xBRZ = 4×BRZ TexMMPX = MMPX @@ -1016,8 +1015,10 @@ Size = Taille Uninstall = Désinstaller [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d par cœur, %d cœurs) %d bytes = %d octets +%d Hz = %d Hz (none detected) = (aucun détecté) 3D API = API 3D ABI = ABI @@ -1035,6 +1036,7 @@ CPU Name = Nom D3DCompiler Version = Version de D3DCompiler Debug = Débogage Debugger Present = Débogueur présent +Depth buffer format = Depth buffer format Device Info = Informations sur l'appareil Directories = Directories Display Color Formats = Display Color Formats @@ -1090,6 +1092,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Langue Memory Stick folder = Changer le dossier de la Memory Stick Memory Stick size = Changer la taille de la Memory Stick (Go) Change Nickname = Changer de pseudo @@ -1211,3 +1215,17 @@ Details = Détails Dismiss = Ignorer Download = Télécharger New version of PPSSPP available = Nouvelle version de PPSSPP disponible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index f644af1246..87ab725d79 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -129,7 +129,6 @@ Backend = Motor &gráfico (require reiniciar) Bicubic = &Bicúbico Break = Break Break on Load = Break on load -Buffered Rendering = &Renderizado por búfer Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botóns... Debugging = &Depuración @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = &Volcar seguinte cadro a rexistro Emulation = &Emulación @@ -173,7 +172,7 @@ Log Console = Consola de re&xistros... Memory View... = Visor de &memoria... More Settings... = Máis &opcións... Nearest = &Cercano -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Non Open Chat = Open Chat Open Directory... = &Abrir carpeta... @@ -185,7 +184,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar ó cambiar de ventá Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = &Shader de postprocesado PPSSPP Forums = &Foro de PPSSPP Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Volcar EBOOT.BIN descifrado ó iniciar o xogo -Dump Frame GPU Commands = Volcar comandos GPU do cadro +Dump next frame to log = Volcar seguinte cadro ó rexistro Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Activar rexistro Enter address = Insertar dirección @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Comparación JIT JIT debug tools = JIT debug tools -Language = Idioma -Load language ini = Cargar INI de idioma Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Nivel de rexistro Log View = Ver o rexistro @@ -262,7 +258,6 @@ RestoreDefaultSettings = Seguro que queres volver ós axustes de fábrica?\nOs c RestoreGameDefaultSettings = Seguro que queres reestablecer os axustes do xogo\nós axustes por defecto de PPSSPP? Resume = Resume Run CPU Tests = Probas de CPU -Save language ini = Gardar INI de idioma Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Mostrar menú de desenrolo @@ -318,6 +313,8 @@ Load completed = Carga completada. Loading = Cargando\nAgarda un momento... LoadingFailed = Os datos nom se puideron cargar. Move = Posición +Move Down = Move Down +Move Up = Move Up Network Connection = Conexión de rede NEW DATA = NOVOS DATOS No = Non @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Aceptar Old savedata detected = Detectados datos de gardado antigos. Options = Options +Remove = Remove Reset = Reiniciar Resize = Tamaño Retry = Reintentar @@ -460,6 +458,8 @@ Aggressive = Agresivo Alternative Speed = Velocidade alternativa (%, 0 = ilimitada) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtrado anisotrópico +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Automático (igual á de renderizado) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Motor gráfico Balanced = Balanceado Bicubic = Bicúbico -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Renderizado por búfer BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) -Dump next frame to log = Volcar seguinte cadro ó rexistro Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Control de tasa de cadros (FPS) Frame Skipping = Saltar cadros Frame Skipping Type = Frame skipping type FullScreen = Pantalla completa -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Axustes de hacks (causarán erros gráficos) Hardware Tessellation = Hardware tessellation Hardware Transform = Transformación por hardware @@ -525,7 +522,7 @@ Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa do dispositivo Nearest = Pixelado No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Non Number of Frames = Number of frames Off = Non @@ -534,28 +531,27 @@ Overlay Information = Información en pantalla Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Rendemento -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Shader de postprocesado +Postprocessing shaders = Shaders de postprocesado Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Modo de renderizado Rendering Resolution = Resolución de renderizado RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Seguro -Screen layout = Screen layout Screen Scaling Filter = Filtro de escalado de pantalla Show Debug Statistics = Mostrar estadísticas de depuración Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderizado por software (beta) Software Skinning = «Skinning» por software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Velocidade -Stretching = Stretching +Speed Hacks = Speed Hacks (causarán erros gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Filtro de texturas Texture Filtering = Filtrado de texturas Texture Scaling = Escalado de texturas @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA + cor Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Debuxos animados CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Monitor con «scanlines» (CRT) FXAA = Antialiasing FXAA Gamma = Gamma -Grayscale = Escala de grises +GreenLevel = Green level Intensity = Intensity -InverseColors = Invertir cores +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Cores naturais NaturalA = Natural Colors (no blur) Off = Non Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Afiado +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Tamaño Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Idioma Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Cambiar alcume PSP @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Cancelar Download = Descargar New version of PPSSPP available = Nova versión de PPSSPP dispoñible + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 51df0a1cd9..174241a6ee 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -129,7 +129,6 @@ Backend = Σύστημα Υποστήριξης (επανεκκινεί το PPS Bicubic = &Διακυβική Break = Break Break on Load = Break on load -Buffered Rendering = Απεικόνιση με Buffer Buy Gold = Αγορά &Gold Control Mapping... = Χαρτογράφηση Κουμπιών... Debugging = Αποσφαλμάτωση @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = Αποσυναρμολόγηση... Discord = Discord -Display Layout Editor = Επεξεργασία διάταξης οθόνης... +Display Layout && Effects = Επεξεργασία διάταξης οθόνης... Display Rotation = Περιστροφή Οθόνης Dump Next Frame to Log = Αποτύπωση πλαισίου σε καταγραφέα Emulation = Εξομοίωση @@ -173,7 +172,7 @@ Log Console = Κονσόλα Καταγραφέα Memory View... = Προβολή Μνήμης... More Settings... = Περισσότερες Ρυθμίσεις... Nearest = Κοντινότερο -Non-Buffered Rendering = &Παράκαμψη εφέ buffer (γρηγορότερο) +Skip Buffer Effects = &Παράκαμψη εφέ buffer (γρηγορότερο) Off = &Off Open Chat = Open Chat Open Directory... = Άνοιγμα Φακέλου... @@ -185,7 +184,6 @@ Pause = &Πάυση Pause When Not Focused = Παύση σε κατάσταση παρασκηνίου Portrait = Κατακόρυφο προσανατολισμός Portrait reversed = Αντεστραμένος κατακόρυφος προσανατολισμός -Postprocessing Shader = Shader Μετεπεξεργασίας PPSSPP Forums = PPSSPP &Forum Record = Καταγραφή Record Audio = Καταγραφή Ήχου @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Εξαγωγή αποκρυπτογραφημένου EBOOT.BIN κατά την έναρξη -Dump Frame GPU Commands = Εξαγωγή εντολών frame GPU +Dump next frame to log = Αποτύπωση πλαισίου σε καταγραφέα Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ενεργοποίηση καταγραφής αποσφαλμάτωσης Enter address = Διεύθυνση Enter @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profiler πλαισίου GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Σύγκριση Jit JIT debug tools = JIT debug tools -Language = Γλώσσα -Load language ini = Φόρτωση ini γλώσσας Log Dropped Frame Statistics = Καταγραφή Στατιστικών για Dropped Frames Log Level = Επίπεδο καταγραφής Log View = Εμφάνιση καταγραφέα @@ -262,7 +258,6 @@ RestoreDefaultSettings = Είστε σίγουροι ότι θέλετε να ε RestoreGameDefaultSettings = Είστε σίγουροι ότι θέλετε να επαναφέρετε τις ρυθμίσεις παιχνιδιού\nστις προεπιλεγμένες του PPSSPP; Resume = Resume Run CPU Tests = Εκκίνηση τέστ CPU -Save language ini = Αποθήκευση ini γλώσσας Save new textures = Αποθήκευση νέων υφών Shader Viewer = Προβολέας Shader Show Developer Menu = Εμφάνιση μενού προγραμματιστών @@ -318,6 +313,8 @@ Load completed = ΦΟΡΤΩΣΗ ΟΛΟΚΛΗΡΩΘΗΚΕ Loading = ΦΟΡΤΩΣΗ\nΠΑΡΑΚΑΛΩ ΠΕΡΙΜΕΝΕΤΕ... LoadingFailed = ΑΔΥΝΑΜΙΑ ΦΟΡΤΩΣΗΣ ΔΕΔΟΜΕΝΩΝ. Move = ΜΕΤΑΚΙΝΗΣΗ +Move Down = Move Down +Move Up = Move Up Network Connection = ΣΥΝΔΕΣΗ ΔΙΚΤΥΟΥ NEW DATA = ΝΕΑ ΔΕΔΟΜΕΝΑ No = ΟΧΙ @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Εντοπίστηκαν παλαιά αρχεία αποθήκευσης Options = ΕΠΙΛΟΓΕΣ +Remove = Remove Reset = ΕΠΑΝΑΦΟΡΑ Resize = ΑΛΛΑΓΗ ΜΕΓΕΘΟΥΣ Retry = ΕΠΑΝΑΛΗΨΗ @@ -460,6 +458,8 @@ Aggressive = Εξαναγκαστική Alternative Speed = Εναλακτική προβολή ταχύτητας (στα %, 0 = απεριόριστη) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Ανισοτροπικό Φιλτράρισμα +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Αυτόματο Auto (1:1) = Αυτόματο (1:1) Auto (same as Rendering) = Αυτόματο (ίσο με την Ανάλυση Απεικόνισης) @@ -469,11 +469,8 @@ Auto Scaling = Αυτόματη Κλιμάκωση Backend = Σύστημα Υποστήριξης Balanced = Εξισορροπημένη Bicubic = Διακυβική -BlockTransfer Tip = Ορισμένα παιχνίδια απαιτούν να είναι ενεργοποιημένο για την σωστή επεικόνιση γραφικών. -BlockTransferRequired = Προειδοποίηση: Αυτό το παιχνίδι απαιτεί τη λειτουργία προσομοίωσης εφέ μεταφοράς block να είναι ενεργοποιημένη. Both = Όλα Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Απεικόνιση με Buffer BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Απενεργοποιημένο -Display layout editor = Επεξεργασία διάταξης οθόνης +Display Layout && Effects = Επεξεργασία διάταξης οθόνης Display Resolution (HW scaler) = Ανάλυση οθόνης (Κλιμακοτής hardware) -Dump next frame to log = Αποτύπωση πλαισίου σε καταγραφέα Enable Cardboard VR = Ενεργοποίηση Cardboard VR FPS = FPS Frame Rate Control = Ρυθμίσεις Ρυθμού Καρέ Frame Skipping = Παράκαμψη Καρέ Frame Skipping Type = Frame skipping type FullScreen = Πλήρης Οθόνη -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ρυθμίσεις Hack Hardware Tessellation = Tessellation Υλικού Hardware Transform = Μετασχηματισμός Υλικού @@ -525,7 +522,7 @@ Must Restart = Πρέπει να επανεκκινήσετε το PPSSPP για Native device resolution = Χρήση ανάλυσης συσκευής Nearest = Κοντινότερο No buffer = No buffer -Non-Buffered Rendering = Παράκαμψη εφέ buffer (γρηγορότερο) +Skip Buffer Effects = Παράκαμψη εφέ buffer (γρηγορότερο) None = Καμία Number of Frames = Number of frames Off = Ανενεργό @@ -534,28 +531,27 @@ Overlay Information = Πληροφορίες Οθόνης Partial Stretch = Μερική επέκταση Percent of FPS = Percent of FPS Performance = Επίδοσεις -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Shader Μετεπεξεργασίας +Postprocessing shaders = Shaders Μετεπεξεργασίας Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Τρόπος Απεικόνισης Rendering Resolution = Ανάλυση Απεικόνισης RenderingMode NonBuffered Tip = Γρηγορότερο, αλλά σε μερικά αιχνίδια μπορεί να μην εμφανίζει τίποτα -Retain changed textures = Διατηρήστε αλλαγμένων υφών (μερικές φορές αργότερο) -RetainChangedTextures Tip = Κάνει πολλά παιχνίδια πιο αργά, αλλά κάποια άλλα πιο γρήγορα Rotation = Περιστροφή Safe = Ασφαλής -Screen layout = Screen layout Screen Scaling Filter = Φίλτο κλιμάκωσης οθόνης Show Debug Statistics = Εμφάνιση στατιστικών αποσφαλμάτωσης Show FPS Counter = Εμφάνιση μετρητή FPS -Simulate Block Transfer = Προσομοίωση εφέ μεταφοράς block +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Απεικόνιση Λογισμικού (πειραματικό) Software Skinning = Εκδορά Λογισμικού SoftwareSkinning Tip = Συνδυασμός μοντέλου στην CPU, γρηγορότερο στα περισσότερα παιχνίδια Speed = Ταχύτητα -Stretching = Επέκταση +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Επέκταση Texture Filter = Φίλτρο Υφών Texture Filtering = Φιλτράρισμα Υφών Texture Scaling = Κλιμάκωση Υφών @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Καρτούν CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Γραμμές σάρωσης CRT FXAA = Εξομάλυνση κορυφών FXAA Gamma = Gamma -Grayscale = Ασπρόμαυρο +GreenLevel = Green level Intensity = Intensity -InverseColors = Αντιστροφή Χρωμάτων +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Φυσικά Χρώματα NaturalA = Natural Colors (no blur) Off = Ανενεργό Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Γραμμές Σάρωσης (CRT) Sharpen = Όξυνση +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Μέγεθος Uninstall = Απεγκατάσταση [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d ανά πυρήνα, %d πυρήνες) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (δεν βρέθηκε) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Όνομα D3DCompiler Version = Έκδοση D3DCompiler Debug = Εντοπισμός σφαλμάτων Debugger Present = Παρουσία πρόγραμματος εντοπισμού σφαλμάτων +Depth buffer format = Depth buffer format Device Info = Πληροφορίες συσκευής Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Γλώσσα Memory Stick folder = Αλλαγή φακέλου Memory Stick Memory Stick size = Memory Stick size Change Nickname = Αλλαγή Ψευδωνύμου @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Απόρριψη Download = Κατέβασμα New version of PPSSPP available = Νέα διαθέσιμη έκδοση PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 95cda4cb26..8d01a00e32 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &מאגר מעובד Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = ניפ&וי @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &פירוק... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &סימולציה @@ -173,7 +172,7 @@ Log Console = &התחבר לקונסולה Memory View... = הצג &זיכרון... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = פתח &קובץ... @@ -185,7 +184,6 @@ Pause = &השהה Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = בחר את הפריים הבא כדי לדווח Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = אפשר דיווח באגים Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = שפה -Load language ini = טען קובץ שפה Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = הרץ בדיקות מעבד -Save language ini = שמור קובץ שפה Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = .המלשוה הניעט Loading = ...ןתמה אנא ...ןעוט LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = םישדח םינותנ No = אל @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = רדסב Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = הגבלת מהירות Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = אוטומטי Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = שניהם Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = מאגר מעובד BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = בחר את הפריים הבא כדי לדווח Enable Cardboard VR = Enable Cardboard VR FPS = כמות פריימים לשנייה Frame Rate Control = שליטה על קצב פריימים Frame Skipping = דלג על פריימים Frame Skipping Type = Frame skipping type FullScreen = מסך מלא -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = התאמת חומרה @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = הקרוב ביותר No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = אל תציג מונה Number of Frames = Number of frames Off = כבוי @@ -534,28 +531,27 @@ Overlay Information = כיסוי מידע Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = מצב מעובד Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = הצג סטטיסטיקת באגים Show FPS Counter = הצג מונה -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = עיבוד תוכנה (ניסיוני) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = מהירות -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = קידוד טקסטורה Texture Filtering = קידוד טקסטורה Texture Scaling = מידת טקסטורה @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = שפה Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = שנה כינוי @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index ee1ed7aced..a96b45ad00 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = Debu&g @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = חוודל ידכ אבה םיירפה תא רחב Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = םיגאב חוויד רשפא Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = הפש -Load language ini = הפש ץבוק ןעט Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = דבעמ תוקידב ץרה -Save language ini = הפש ץבוק רומש Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = .המלשוה הניעט Loading = ...ןתמה אנא ...ןעוט LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = םישדח םינותנ No = אל @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = רדסב Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = תוריהמ תלבגה Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = יטמוטוא Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = םהינש Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = דבועמ רגאמ BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = חוודל ידכ אבה םיירפה תא רחב Enable Cardboard VR = Enable Cardboard VR FPS = היינשל םימיירפ תומכ Frame Rate Control = םימיירפ בצק לע הטילש Frame Skipping = םימיירפ לע גלד Frame Skipping Type = Frame skipping type FullScreen = אלמ ךסמ -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = הרמוח תמאתה @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = רתויב בורקה No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = הנומ גיצת לא Number of Frames = Number of frames Off = יובכ @@ -534,28 +531,27 @@ Overlay Information = עדימ יוסיכ Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = דבועמ בצמ Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = םיגאב תקיטסיטטס גצה Show FPS Counter = הנומ גצה -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = )ינויסינ( הנכות דוביע Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = תוריהמ -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = הרוטסקט דודיק Texture Filtering = הרוטסקט דודיק Texture Scaling = הרוטסקט תדימ @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = הפש Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = יוניכ הנש @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 8238d63b17..c78c6187eb 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -129,7 +129,6 @@ Backend = Poslužitelj &renderanja (restarta PPSSPP) Bicubic = &Bikubično Break = Pokvari Break on Load = Pokvari na učitavanju -Buffered Rendering = &Buffano prikazivanje Buy Gold = Kupi &Gold Control Mapping... = P&ostavljanje kontroli... Debugging = &Debug @@ -138,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Prikaži uređivanje kontroli... +Display Layout && Effects = Prikaži uređivanje kontroli... Display Rotation = Rotacija prikaza Dump Next Frame to Log = O&dloži sljedeći frame na log Emulation = &Emulacija @@ -173,7 +172,7 @@ Log Console = &Konzola log-a Memory View... = Pregled &memorije... More Settings... = &Više postavki... Nearest = &Najbliže -Non-Buffered Rendering = &Preskoči bufferane efekte (non-buffered, faster) +Skip Buffer Effects = &Preskoči bufferane efekte Off = &Off Open Chat = Open Chat Open Directory... = Otvori &direktorij... @@ -185,7 +184,6 @@ Pause = &Pauza Pause When Not Focused = &Pauziraj kad nije fokusirano Portrait = Portret Portrait reversed = Obrnuti portret -Postprocessing Shader = Postupa&k sjenčanja PPSSPP Forums = PPSSPP &forumi Record = &Snimaj Record Audio = Snimaj &zvuk @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Isključena JIT funkcionalnost Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Odbaci sljedeći frame u log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Uključi debug logging Enter address = Upiši adresu @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = Testiranje GPU drivera -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profil Jit Compare = JIT uspoređivanje JIT debug tools = JIT debug alati -Language = Jezik -Load language ini = Učitaj language ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log pregled @@ -262,7 +258,6 @@ RestoreDefaultSettings = Jesi li siguran da želiš vratiti sve postavke na zada RestoreGameDefaultSettings = Jesi li siguran da želiš vratiti igrom-specifične postavke \nna PPSSPP zadane postavke? Resume = Resume Run CPU Tests = Pokreni CPU testove -Save language ini = Spremi language ini Save new textures = Spremi nove teksture Shader Viewer = Pregled sjenčanja Show Developer Menu = Prikaži developer izbornik @@ -318,6 +313,8 @@ Load completed = Učitavanje dovršeno. Loading = Učitavanje\nPričekajte... LoadingFailed = Nije moguće učitati datu. Move = Pomakni +Move Down = Move Down +Move Up = Move Up Network Connection = Internetska veza NEW DATA = NOVA DATA No = Ne @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Uočena stara savedata Options = Opcije +Remove = Remove Reset = Reset Resize = Resize Retry = Ponovi @@ -460,6 +458,8 @@ Aggressive = Agresivno Alternative Speed = Alternativna brzina (u %, 0 = unlimited) Alternative Speed 2 = Alternativna brzina 2 (u %, 0 = unlimited) Anisotropic Filtering = Anizotropno filtriranje +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (isto kao Prikazna rezolucija) @@ -469,11 +469,8 @@ Auto Scaling = Auto mjerenje Backend = Backend Balanced = Balansirano Bicubic = Bikubično -BlockTransfer Tip = Neke igre zahtijevaju ovo na Uključeno za točne grafike -BlockTransferRequired = Upozorenje: Ova igra zahtijeva "simulirajte blok transfer efekte" da budu postavljeni na Uključeno. Both = Oboje Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Ublaživanje prikaza BufferedRenderingRequired = Upozorenje: Ova igra zahtijeva "prikazni način" da bude postavljen na "ublaženo". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Uređaj Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Isključeno -Display layout editor = Prikaz layout uređivača +Display Layout && Effects = Prikaz layout uređivača Display Resolution (HW scaler) = Prikaz rezolucije (HW mjeritelj) -Dump next frame to log = Odbaci sljedeći frame u log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate kontrole Frame Skipping = Preskakanje sličica Frame Skipping Type = Vrsta preskakanja sličica FullScreen = Puni zaslon -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Opcije hakiranja (može uzrokovati glitcheve) Hardware Tessellation = Hardware tesselacija Hardware Transform = Hardver mozaik @@ -525,7 +522,7 @@ Must Restart = Morate ponovno pokrenuti PPSSPP da bi se efekat primjenio. Native device resolution = Urođena rezolucija uređaja Nearest = Najbliže No buffer = No buffer -Non-Buffered Rendering = Preskoči efekte ublaživanja (nije ublaženo, faster) +Skip Buffer Effects = Preskoči efekte ublaživanja (nije ublaženo, faster) None = Nijedna Number of Frames = Broj frame-ova Off = Isključeno @@ -534,28 +531,27 @@ Overlay Information = Prekrivanje informacija Partial Stretch = Djelomično rastezanje Percent of FPS = Postotak FPS-a Performance = Performansa -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Sjenčanje poslije procesa +Postprocessing shaders = Sjenčanje poslije procesa Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Izlgađiva frameove u igrama koje ih jako malo imaju Rendering Mode = Način prikaza Rendering Resolution = Rezolucija prikaza RenderingMode NonBuffered Tip = Brže, ali ništa može uvući neke igre -Retain changed textures = Ostavi promijenjene teksture (ponekad sporije) -RetainChangedTextures Tip = Usporava mnogo igara, ali neke igre dosta ubrzava Rotation = Rotacija Safe = Sigurno -Screen layout = Screen layout Screen Scaling Filter = Mjerenje filtriranje zaslona Show Debug Statistics = Pokaži statistike otklanjanja grešaka Show FPS Counter = Pokaži FPS counter -Simulate Block Transfer = Simuliraj blok transfer efekte +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Žbukanje softvera (sporo) Software Skinning = Skiniranje softvera SoftwareSkinning Tip = Kombiniraj skinirane modele crteža na CPU, brže u većini igara Speed = Brzina -Stretching = Rastezanje +Speed Hacks = Speed Hacks (može uzrokovati glitcheve) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Rastezanje Texture Filter = Filtar tekstura Texture Filtering = Filtriranje tekstura Texture Scaling = Mjerenje tekstura @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Izmijeni boje +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Prirodne boje NaturalA = Prirodne boje (bez zamućivanja) Off = Isključeno Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Naoštriti +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Veličina Uninstall = Deinstaliraj [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d po jezgri, %d jezgre) %d bytes = %d bajtova +%d Hz = %d Hz (none detected) = (nijedna uočena) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Ime D3DCompiler Version = D3DCompiler verzija Debug = Otklanjanje grešaka Debugger Present = Otklanjivač grešaka prisutan +Depth buffer format = Depth buffer format Device Info = Informacije o uređaju Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Jezik Memory Stick folder = Promijeni mapu Memorijskoga sticka Memory Stick size = Memory Stick size Change Nickname = Promijeni nadimak @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Zanemari Download = Instaliraj New version of PPSSPP available = Nova verzija PPSSPP-a je dostupna + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 13078c4f7f..6d93830448 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -129,7 +129,6 @@ Backend = Renderelési &backend (újraindítás szükséges) Bicubic = &Bicubic Break = Megállítás Break on Load = Megállítás betöltéskor -Buffered Rendering = &Bufferelt renderelés Buy Gold = &Gold vásárlása Control Mapping... = &Gombok beállítása… Debugging = &Hibakeresés @@ -138,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D 1&1 Disassembly = &Disassembly… Discord = &Discord -Display Layout Editor = Elrendezés szerkesztő… +Display Layout && Effects = Elrendezés szerkesztő… Display Rotation = Megjelenítés forgatása Dump Next Frame to Log = Kö&vetkező képkocka kiírása naplófájlba Emulation = &Emuláció @@ -173,7 +172,7 @@ Log Console = &Napló ablak Memory View... = Memória &nézet… More Settings... = &Egyéb beállítások… Nearest = Leg&közelebbi -Non-Buffered Rendering = Bufferelt effektek kihagyá&sa (nem bufferelt, gyorsabb) +Skip Buffer Effects = Bufferelt effektek kihagyá&sa (nem bufferelt, gyorsabb) Off = &Ki Open Chat = Open Chat Open Directory... = Ma&ppa megnyitása… @@ -185,7 +184,6 @@ Pause = &Szünet Pause When Not Focused = &Szüneteltetés, ha nincs fókuszban Portrait = Álló Portrait reversed = Fordított álló -Postprocessing Shader = Utóeffektező shader PPSSPP Forums = PPSSPP &fórum Record = &Felvétel Record Audio = &Hang felvétele @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Kikapcsolt JIT funkcionalitások Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Visszafejtett EBOOT.BIN írása játék indításakor -Dump Frame GPU Commands = Képkocka GPU parancsok írása +Dump next frame to log = Következő képkocka kiírása naplófájlba Enable Logging = Naplózás engedélyezése Enable driver bug workarounds = Enable driver bug workarounds Enter address = Cím megadása @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Képkocka profilozó GPU Driver Test = GPU driver teszt -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profil Jit Compare = JIT összehasonlítás JIT debug tools = JIT hibakereső eszközök -Language = Nyelv -Load language ini = Nyelvi .ini betöltése Log Dropped Frame Statistics = Eldobott képkockák statisztikáinak naplózása Log Level = Naplózási szint Log View = Nápló megtekintése @@ -262,7 +258,6 @@ RestoreDefaultSettings = Biztos vagy benne, hogy mindent az alapértelmezettre RestoreGameDefaultSettings = Biztos vagy benne, hogy minden játék-specifikus beállítást\nvisszaállítáasz a PPSSPP alapértelmezettre? Resume = Resume Run CPU Tests = CPU tesztek futtatása -Save language ini = Nyelvi .ini mentése Save new textures = Új textúrák mentése Shader Viewer = Shader megjelenítő Show Developer Menu = Fejlesztői menü megjelenítése @@ -318,6 +313,8 @@ Load completed = Betöltve. Loading = Betöltés\nKérlek várj... LoadingFailed = Betöltés sikertelen. Move = Mozgat +Move Down = Move Down +Move Up = Move Up Network Connection = Hálózati kapcsolat NEW DATA = ÚJ MENTÉS No = Nem @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Régi mentés észlelve Options = Opciók +Remove = Remove Reset = Visszaállít Resize = Átméretez Retry = Újra @@ -460,6 +458,8 @@ Aggressive = Agresszív Alternative Speed = Alternatív sebesség Alternative Speed 2 = Alternatív sebesség 2 (%-ban, 0 = korlátlan) Anisotropic Filtering = Anizotropikus szűrés +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (renderelési felbontással megegyező) @@ -469,11 +469,8 @@ Auto Scaling = Automatikus skálázás Backend = Backend Balanced = Kiegyensúlyozott Bicubic = Bicubic -BlockTransfer Tip = Néhány játék számára ezt be kell kapcsolni ahhoz, hogy helyesen rajzolódjon ki. -BlockTransferRequired = Figyelem: Ehhez a játékhoz be kell kapcsolni a "Blokk transzfer effektek szimulálása" opciót! Both = Mindkettő Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Bufferelt renderelés BufferedRenderingRequired = Figyelem: Ehhez a játékhoz a "Renderelési mód" beállítást "Bufferelt"-re kell állítani! Camera = Kamera Camera Device = Kamera eszköz @@ -491,16 +488,16 @@ Device = Eszköz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Letiltva -Display layout editor = Elrendezés szerkesztő +Display Layout && Effects = Elrendezés szerkesztő Display Resolution (HW scaler) = Megjelenítési felbontás (HW skálázó) -Dump next frame to log = Következő képkocka kiírása naplófájlba Enable Cardboard VR = Cardboard VR engedélyezése FPS = FPS Frame Rate Control = Képkocka sebesség szabályozása Frame Skipping = Képkocka kihagyás Frame Skipping Type = Képkocka kihagyás típusa FullScreen = Teljes képernyő -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack beállítások (ezek HIBÁKAT OKOZHATNAK) Hardware Tessellation = Hardveres tesszeláció Hardware Transform = Hardveres transzform @@ -525,7 +522,7 @@ Must Restart = A beállítások érvénybeléptetéséhez újra kell indítani a Native device resolution = Natív készülék felbontás Nearest = Legközelebbi No buffer = No buffer -Non-Buffered Rendering = Buffer effektek kihagyása (nem bufferelt, gyorsabb) +Skip Buffer Effects = Buffer effektek kihagyása (nem bufferelt, gyorsabb) None = Nincs Number of Frames = Képkockák száma Off = Ki @@ -534,28 +531,27 @@ Overlay Information = Overlay információk Partial Stretch = Részleges nyújtás Percent of FPS = FPS százalékában Performance = Teljesítmény -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Utóeffektező shader +Postprocessing shaders = Utóeffektező shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Képkockák duplázása 60 Hz rendereléshez RenderDuplicateFrames Tip = Simábbá teheti az alacsonyabb képkocka számon futó játékok kirajzolását Rendering Mode = Renderelés módja Rendering Resolution = Renderelés felbontása RenderingMode NonBuffered Tip = Gyorsabb, de egyes játékokban nem rajzol ki semmit. -Retain changed textures = Változtatott textúrák megtartása (olykor lassabb) -RetainChangedTextures Tip = Egyes játékokat gyorsít, de sok játékot lassít. Rotation = Forgatás Safe = Biztonságos -Screen layout = Screen layout Screen Scaling Filter = Képernyő skálázási szűrő Show Debug Statistics = Hibakeresési statisztikák mutatása Show FPS Counter = FPS számláló mutatása -Simulate Block Transfer = Blokk transzfer effektek szimulálása +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Szoftveres renderelés (lassú) Software Skinning = Szoftveres "skinning" SoftwareSkinning Tip = "Skinning" művelet elvégzése a processzoron. Sok játék esetében gyorsabb. Speed = Sebesség -Stretching = Nyújtás +Speed Hacks = Speed Hacks (ezek HIBÁKAT OKOZHATNAK) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Nyújtás Texture Filter = Textúra szűrés Texture Filtering = Textúra szűrés Texture Scaling = Textúra nagyítás @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Mennyiség Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Rajzfilm CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Színkorrekció +ColorPreservation = Color preservation Contrast = Kontraszt CRT = CRT FXAA = FXAA élsimítás Gamma = Gamma -Grayscale = Szürkeárnyalatos +GreenLevel = Green level Intensity = Erősség -InverseColors = Színek megfordítása +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Természetes színek NaturalA = Természetes színek (elmosódás nélkül) Off = Ki Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Telítettség (szaturáció) Scanlines = Csíkozás Sharpen = Élesítés +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Méret Uninstall = Eltávolítás [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d magonként, %d db mag) %d bytes = %d bájt +%d Hz = %d Hz (none detected) = (nem észlelve) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Név D3DCompiler Version = D3DCompiler verzió Debug = Hibakeresés Debugger Present = Debugger jelen +Depth buffer format = Depth buffer format Device Info = Eszközinfó Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Nyelv Memory Stick folder = Memory Stick mappa megváltoztatása Memory Stick size = Memory Stick size Change Nickname = Becenév megváltoztatása @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Kihagyás Download = Letöltés New version of PPSSPP available = Elérhető a PPSSPP egy újabb verziója + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 00af881bf1..84334eb1a4 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -129,7 +129,6 @@ Backend = Bangun pelukisan &penyangga grafis (mulai ulang PPSSPP) Bicubic = &Bikubik Break = Rusak Break on Load = Rusak pada pemuatan -Buffered Rendering = Pelukisan tersangga Buy Gold = Beli versi &Emas Control Mapping... = Pemetaan k&ontrol... Debugging = Awakutu @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D11 Disassembly = &Pembongkaran... Discord = Discord -Display Layout Editor = Penyunting tata letak tampilan... +Display Layout && Effects = Penyunting tata letak tampilan... Display Rotation = Rotasi tampilan Dump Next Frame to Log = B&uang laju bingkai berikutnya untuk masuk Emulation = &Emulasi @@ -173,7 +172,7 @@ Log Console = Konso&l pencatat Memory View... = Tampilan memori... More Settings... = Pengaturan lainnya... Nearest = Terdekat -Non-Buffered Rendering = Lewati efek penyangga (tak-tersangga, lebih cepat) +Skip Buffer Effects = Lewati efek penyangga (tak-tersangga, lebih cepat) Off = Mati Open Chat = Buka opsi obrolan Open Directory... = Buka &direktori... @@ -185,7 +184,6 @@ Pause = Jeda Pause When Not Focused = Jeda ketika tidak fokus Portrait = Tegak Portrait reversed = Tegak terbalik -Postprocessing Shader = Pemrosesan shader PPSSPP Forums = &Forum PPSSPP Record = Rekam Record Audio = Rekam suara @@ -233,7 +231,7 @@ DevMenu = Menu pengembang Disabled JIT functionality = Fungsi JIT dinonaktifkan Draw Frametimes Graph = Gambar grafis sketsa waktu Dump Decrypted Eboot = Buang EBOOT.BIN yang didekripsi pada pengaktifan ulang permainan -Dump Frame GPU Commands = Buang perintah laju bingkai GPU +Dump next frame to log = Buang laju bingkai selanjutnya untuk masuk Enable driver bug workarounds = Aktifkan solusi masalah driver Enable Logging = Hidupkan pencatat awakutu Enter address = Masukkan alamat @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Tes pembuangan laju bingkai Frame Profiler = Profil laju bingkai GPU Driver Test = Tes driver GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Profil GPU Jit Compare = Bandingkan Jit JIT debug tools = Alat awakutu JIT -Language = Bahasa -Load language ini = Muat *.ini bahasa Log Dropped Frame Statistics = Log statistik laju bingkai yang jatuh Log Level = Tingkatan pencatat Log View = Tampilan pencatat @@ -262,7 +258,6 @@ RestoreDefaultSettings = Apakah Anda yakin ingin mengembalikan semua pengaturan RestoreGameDefaultSettings = Apakah Anda yakin ingin mengembalikan pengaturan permainan\nkembali ke pengaturan awal PPSSPP? Resume = Lanjutkan Run CPU Tests = Jalankan pengujian CPU -Save language ini = Simpan *.ini bahasa Save new textures = Simpan tekstur baru Shader Viewer = Penampil shader Show Developer Menu = Tampilkan menu pengembang @@ -318,6 +313,8 @@ Load completed = Selesai memuat. Loading = Memuat\nMohon Tunggu... LoadingFailed = Tidak dapat memuat data. Move = Pindah +Move Down = Move Down +Move Up = Move Up Network Connection = Koneksi Jaringan NEW DATA = DATA BARU No = Tidak @@ -325,6 +322,7 @@ ObtainingIP = Mendapatkan alamat IP.\nHarap tunggu... OK = Oke Old savedata detected = Simpanan data lama terdeteksi Options = Pilihan +Remove = Remove Reset = Atur ulang Resize = Atur ulang ukuran Retry = Coba lagi @@ -460,6 +458,8 @@ Aggressive = Agresif Alternative Speed = Kecepatan alternatif (dalam %, 0 = tak terbatas) Alternative Speed 2 = Kecepatan alternatif 2 (dalam %, 0 = tak terbatas) Anisotropic Filtering = Pemfilteran anisotropik +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Otomatis Auto (1:1) = Otomatis (1:1) Auto (same as Rendering) = Otomatis (sama dengan resolusi pelukis) @@ -469,11 +469,8 @@ Auto Scaling = Penskala otomatis Backend = Penyangga grafis Balanced = Seimbang Bicubic = Bikubik -BlockTransfer Tip = Beberapa permainan memerlukan opsi ini untuk menghindari kesalahan grafis. -BlockTransferRequired = Peringatan: Permainan ini membutuhkan "Simulasikan efek transfer blok" dalam keadaan menyala. Both = Keduanya Buffer graphics commands (faster, input lag) = Perintah grafis penyangga (lebih cepat, masukan lag) -Buffered Rendering = Pelukisan tersangga BufferedRenderingRequired = Peringatan: Permainan ini membutuhkan "Mode pelukisan" yang ditetapkan "Penyangga". Camera = Kamera Camera Device = Kamera perangkat @@ -491,16 +488,16 @@ Device = Perangkat Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Nonaktif -Display layout editor = Penyesuaian tata letak tampilan +Display Layout && Effects = Penyesuaian tata letak tampilan Display Resolution (HW scaler) = Resolusi tampilan (penskala HW) -Dump next frame to log = Buang laju bingkai selanjutnya untuk masuk Enable Cardboard VR = Aktifkan Cardboard VR FPS = FPS Frame Rate Control = Kontrol laju bingkai Frame Skipping = Lewati laju bingkai Frame Skipping Type = Jenis lewati laju bingkai FullScreen = Layar penuh -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas pengaturan (menyebabkan kecacatan) Hardware Tessellation = Pengujian perangkat keras Hardware Transform = Transformasi perangkat keras @@ -525,7 +522,7 @@ Must Restart = Anda harus memulai ulang PPSSPP agar perubahan ini berfungsi. Native device resolution = Resolusi asli Nearest = Terdekat No buffer = Tidak ada penyangga -Non-Buffered Rendering = Lewati efek penyangga (tak tersangga, lebih cepat) +Skip Buffer Effects = Lewati efek penyangga (tak tersangga, lebih cepat) None = Tidak ada Number of Frames = Nomor laju bingkai Off = Mati @@ -534,28 +531,27 @@ Overlay Information = Tampilan Informasi Partial Stretch = Peregangan sebagian Percent of FPS = Persen FPS Performance = Kinerja -Postprocessing effect = Efek pemrosesan -Postprocessing Shader = Pemrosesan shader +Postprocessing shaders = Pemrosesan shaders Recreate Activity = Buat ulang aktivitas Render duplicate frames to 60hz = Pelukisan bingkai duplikat menjadi 60 Hz RenderDuplicateFrames Tip = Dapat membuat laju bingkai lebih lancar dalam permainan yang berjalan pada laju bingkai yang lebih rendah Rendering Mode = Mode pelukisan Rendering Resolution = Resolusi pelukisan RenderingMode NonBuffered Tip = Lebih cepat, namun mungkin tidak ada gambar di beberapa permainan -Retain changed textures = Tahan tekstur yang berubah (adakalanya lambat) -RetainChangedTextures Tip = Membuat beberapa permainan lambat, namun beberapa lainnya sangat cepat Rotation = Rotasi Safe = Aman -Screen layout = Tata letak layar Screen Scaling Filter = Pemfilteran penskala layar Show Debug Statistics = Tampilkan statistik awakutu Show FPS Counter = Tampilkan penghitung FPS -Simulate Block Transfer = Simulasikan efek transfer blok +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Pelukisan perangkat lunak (eksperimental) Software Skinning = Pengkulitan perangkat lunak SoftwareSkinning Tip = Menggabungkan model berkulit pada CPU, lebih cepat di kebanyakan permainan Speed = Kecepatan -Stretching = Peregangan +Speed Hacks = Speed Hacks (menyebabkan kecacatan) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Peregangan Texture Filter = Filter tekstur Texture Filtering = Pemfilteran tekstur Texture Scaling = Penskala tekstur @@ -828,9 +824,9 @@ Undo last save = Urungkan penyimpanan terakhir [PostShaders] (duplicated setting, previous slider will be used) = (pengaturan duplikat, penggeser sebelumnya akan digunakan) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Warna AA Amount = Nominal Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Kecerahan Cartoon = Kartun CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Koreksi Warna +ColorPreservation = Color preservation Contrast = Kontras CRT = CRT FXAA = Mengurangi Artifak Distorsi (FXAA) Gamma = Gamma -Grayscale = Abu-abu +GreenLevel = Green level Intensity = Intensitas -InverseColors = Warna Terbalik +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna Natural NaturalA = Warna Natural (tidak kabur) Off = Mati Power = Daya PSPColor = Warna PSP +RedBlue = Red/Blue glasses Saturation = Saturasi Scanlines = Pindai Garis (CRT) Sharpen = Pertajam +SideBySide = Side by side (SBS) SSAA(Gauss) = SSAA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Ukuran Uninstall = Mencopot pemasangan [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d perinti, %d inti) %d bytes = %d bit +%d Hz = %d Hz (none detected) = (tidak ada yang terdeteksi) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Nama CPU D3DCompiler Version = Versi D3DCompiler Debug = Awakutu Debugger Present = Pengawakutu tersedia +Depth buffer format = Depth buffer format Device Info = Info perangkat Directories = Direktori Display Color Formats = Format warna tampilan @@ -1099,6 +1101,8 @@ Color Tint = Pewarnaan Error: load undo state is from a different game = Kesalahan: memuat status yang berasal dari permainan yang berbeda Failed to load state for load undo. Error in the file system. = Gagal memuat status untuk membatalkan pemuatan. Kesalahan dalam sistem berkas. Floating symbols = Simbol mengambang +Game crashed = Game crashed +Language = Bahasa Memory Stick folder = Berkas Memory Stick Memory Stick size = Ukuran Memory Stick Change Nickname = Ganti nama panggilan @@ -1220,3 +1224,17 @@ Details = Rincian Dismiss = Abaikan Download = Unduh New version of PPSSPP available = Versi baru PPSSPP tersedia + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index e52113462f..3b136ec880 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -129,7 +129,6 @@ Backend = Rendering di fondo (riavvia il PPSSPP) Bicubic = Bicubico Break = Interruzione Break on Load = Fermati al caricamento -Buffered Rendering = Rendering con buffer Buy Gold = Acquista la Versione Gold Control Mapping... = Impostazioni dei Controlli... Debugging = Debug @@ -138,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D &11 Disassembly = Disassemblatore... Discord = Discord -Display Layout Editor = Editor visualizzazione layout... +Display Layout && Effects = Editor visualizzazione layout... Display Rotation = Rotazione display Dump Next Frame to Log = Salva Log Frame Successivo Emulation = Emulazione @@ -173,7 +172,7 @@ Log Console = Log Console Memory View... = Visualizzazione Memoria... More Settings... = Altre Impostazioni... Nearest = Pixel perfect -Non-Buffered Rendering = Salta effetti di buffer (niente buffer, più velocità) +Skip Buffer Effects = Salta effetti di buffer (niente buffer, più velocità) Off = Disattiva Open Chat = Apri Chat Open Directory... = Apri Cartella... @@ -185,7 +184,6 @@ Pause = Pausa Pause When Not Focused = Pausa quando non attivo Portrait = Ritratto Portrait reversed = Ritratto invertito -Postprocessing Shader = Shader di post-elaborazione PPSSPP Forums = Forum PPSSPP Record = Registra Record Audio = Registra Audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disattivata Funzionalità JIT Draw Frametimes Graph = Disegna grafica dei frametimes Dump Decrypted Eboot = Crea EBOOT.BIN decriptato all'avvio del gioco -Dump Frame GPU Commands = Comandi GPU Dump frame +Dump next frame to log = Crea Log del Frame Successivo Enable driver bug workarounds = Abilita espediente per superare i bug dei driver Enable Logging = Attiva Log del Debug Enter address = Inserire indirizzo @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Test del framedump Frame Profiler = Profilo Frame GPU Driver Test = Test dei driver GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Profilo GPU Jit Compare = Confronto Jit JIT debug tools = Strumenti di debug JIT -Language = Lingua -Load language ini = Carica *.ini della lingua Log Dropped Frame Statistics = Statistiche dei Frame persi Log Level = Livello del Log Log View = Visualizza Log @@ -262,7 +258,6 @@ RestoreDefaultSettings = Si desidera davvero ripristinare le impostazioni?\nImpo RestoreGameDefaultSettings = Si desidera davvero ripristinare le impostazioni specifiche per il gioco\nai valori predefiniti? Resume = Ripristina Run CPU Tests = Fai Test CPU -Save language ini = Salva *.ini della lingua Save new textures = Salva nuove texture Shader Viewer = Visualizzatore shader Show Developer Menu = Mostra Menu Sviluppatore @@ -318,6 +313,8 @@ Load completed = Caricamento completato. Loading = Caricamento in corso.\nAttendere, prego... LoadingFailed = Impossibile caricare i dati. Move = Sposta +Move Down = Move Down +Move Up = Move Up Network Connection = Connessione di Rete NEW DATA = NUOVI DATI No = No @@ -325,6 +322,7 @@ ObtainingIP = Cerco di ottenere l'indirizzo IP.\nAttendere, prego... OK = OK Old savedata detected = Rilevati vecchi dati salvati Options = Opzioni +Remove = Remove Reset = Reset Resize = Ridimensiona Retry = Riprova @@ -460,6 +458,8 @@ Aggressive = Aggressivo Alternative Speed = Velocità Alternativa (in %, 0 = illimitata) Alternative Speed 2 = Velocità Alternativa 2 (in %, 0 = illimitata) Anisotropic Filtering = Filtro Anisotropico +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatico Auto (1:1) = Automatico (1:1) Auto (same as Rendering) = Automatico (stessa risoluzione del rendering) @@ -469,11 +469,8 @@ Auto Scaling = Scaling automatico Backend = Renderer Balanced = Bilanciato Bicubic = Bicubico -BlockTransfer Tip = Alcuni giochi richiedono che quest'opzione sia attiva per correggere la grafica -BlockTransferRequired = Attenzione: Questo gioco richiede l'attivazione di 'Simula gli effetti del blocco trasferimento'. Both = Entrambi Buffer graphics commands (faster, input lag) = Comandi grafici bufferizzati (più rapido, più lag dei comandi) -Buffered Rendering = Rendering in buffer BufferedRenderingRequired = Attenzione: Questo gioco richiede di impostare "modalità di rendering" su "buffered". Camera = Telecamera Camera Device = Dispositivo di telecamera @@ -490,18 +487,18 @@ Deposterize Tip = Sistema i possibili problemi visivi nelle texture upscalate Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable slower effects (speedup) = Disattiva gli effetti più lenti (veloce) +#Disable slower effects (speedup) = Disattiva gli effetti più lenti (veloce) Disabled = Disabilitato -Display layout editor = Editor Display +Display Layout && Effects = Editor Display Display Resolution (HW scaler) = Risoluzione Display (scaler HW) -Dump next frame to log = Crea Log del Frame Successivo Enable Cardboard VR = Attiva Cardboard VR FPS = FPS Frame Rate Control = Controllo Framerate Frame Skipping = Salto frame Frame Skipping Type = Tipo di Salto frame FullScreen = Schermo Intero -GPU log profiler = Log profilo GPU +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Impostazioni Hack (causerà dei problemi, sicuramente) Hardware Tessellation = Tassellazione Hardware Hardware Transform = Trasformazione Hardware @@ -526,7 +523,7 @@ Must Restart = Sarà necessario riavviare PPSSPP per attivare le modifiche. Native device resolution = Risoluzione nativa della periferica Nearest = Pixel perfect No buffer = Niente buffer -Non-Buffered Rendering = Salta effetti di buffer (niente buffer, più velocità) +Skip Buffer Effects = Salta effetti di buffer (niente buffer, più velocità) None = Nessuno Number of Frames = Numero di Frames Off = Disattiva @@ -535,28 +532,27 @@ Overlay Information = Copri Informazioni Partial Stretch = Estensione Parziale Percent of FPS = Percentuale di FPS Performance = Prestazioni -Postprocessing effect = Effetti di post-elaborazione -Postprocessing Shader = Shader di post-elaborazione +Postprocessing shaders = Shader di post-elaborazione Recreate Activity = Ricrea l'animazione Render duplicate frames to 60hz = Duplica i frame da renderizzare a 60 Hz RenderDuplicateFrames Tip = Può migliorare la fluidità nei giochi che funzionano a frame rate inferiori Rendering Mode = Modalità di Rendering Rendering Resolution = Rendering della Risoluzione RenderingMode NonBuffered Tip = Veloce, ma potrebbe generare dei glitch in alcuni giochi -Retain changed textures = Conserva le textures modificate (a volte è lento) -RetainChangedTextures Tip = Rallenta molti giochi, ma alcuni saranno velocizzati Rotation = Rotazione Safe = Sicuro -Screen layout = Disposizione dello schermo Screen Scaling Filter = Filtro Scalatura Schermo Show Debug Statistics = Mostra Statistiche Debug Show FPS Counter = Mostra FPS -Simulate Block Transfer = Simula gli effetti del blocco trasferimento +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Rendering tramite Software (sperimentale) Software Skinning = Software Skinning SoftwareSkinning Tip = Combina la visualizzazione di modelli disegnati dalla CPU, più veloce nella maggior parte dei giochi Speed = Velocità -Stretching = Adatta al Display +Speed Hacks = Speed Hacks (causerà dei problemi) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Adatta al Display Texture Filter = Filtro delle texture Texture Filtering = Filtraggio delle texture Texture Scaling = Scalatura delle texture @@ -728,6 +724,8 @@ Center Left = Al centro a sinistra Center Right = Al centro a destra Change Mac Address = Cambia indirizzo MAC Change proAdhocServer Address = Cambia indirizzo server IP PRO ad hoc (localhost = istanze multiple) +ChangeMacSaveConfirm = Generate a new MAC address? +ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Chat Chat Button Position = Posizione del pulsante chat Chat Here = Scrivi qui @@ -799,8 +797,8 @@ Undo last save = Annulla ultimo salvataggio [PostShaders] (duplicated setting, previous slider will be used) = (parametri duplicati, verrà usata la precedente regolazione) 4xHqGLSL = 4xHQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Colore AA Amount = Quantità Animation speed (0 -> disable) = Velocità animazione (0 -> disabilita) @@ -810,22 +808,25 @@ Brightness = Luminosità Cartoon = Disegno CatmullRom = Upscaler Bicubico (Catmull-Rom) ColorCorrection = Correzione dei colori +ColorPreservation = Color preservation Contrast = Contrasto CRT = Linee di scansione CRT FXAA = Antialiasing FXAA Gamma = Gamma -Grayscale = Scala di grigi +GreenLevel = Green level Intensity = Intensità -InverseColors = Colori invertiti +LCDPersistence = LCD Persistence MitchellNetravali = Upscaler Bicubico (Mitchell-Netravali) Natural = Colori naturali NaturalA = Colori naturali (nessuna sfocatura) Off = Nessuno Power = Potenza PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturazione Scanlines = Linee di scansione (CRT) Sharpen = Maggior nitidezza +SideBySide = Side by side (SBS) SSAA(Gauss) = Supercampionamento AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1024,8 +1025,10 @@ Size = Dimensioni Uninstall = Disinstalla [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d core) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (niente rilevato) 3D API = API 3D ABI = ABI @@ -1043,6 +1046,7 @@ CPU Name = Nome D3DCompiler Version = Versione D3DCompiler Debug = Debug Debugger Present = Debugger presente +Depth buffer format = Depth buffer format Device Info = Informazioni dispositivo Directories = Cartelle Display Color Formats = Formati colore di visualizzazione @@ -1098,6 +1102,8 @@ Color Tint = Tonalità colore Error: load undo state is from a different game = Errore: lo stato annullato proviene da un gioco diverso. Failed to load state for load undo. Error in the file system. = Impossibile caricare lo stato da un caricamento annullato. Errore nel file system. Floating symbols = Simboli fluttuanti +Game crashed = Game crashed +Language = Lingua Memory Stick folder = Cartella della Memory Stick Memory Stick size = Cambia dimensioni Memory Stick Change Nickname = Cambia Nick @@ -1219,3 +1225,17 @@ Details = Dettagli Dismiss = Ignora Download = Scarica New version of PPSSPP available = È disponibile una nuova versione di PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 10c66c47f1..78be44d9a8 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -2,7 +2,7 @@ Alternate speed volume = カスタム速度時のボリューム Audio backend = オーディオのバックエンド (再起動が必要) Audio Error = オーディオエラー -AudioBufferingForBluetooth = Bluetoothに適したバッファ (低速) +AudioBufferingForBluetooth = Bluetoothに適したバッファ (低遅延) Auto = 自動 Device = デバイス Disabled = Disabled @@ -129,7 +129,6 @@ Backend = バックエンド(&B) Bicubic = Bicubic(&B) Break = ブレーク Break on Load = ロード時にブレーク -Buffered Rendering = バッファレンダリング(&B) Buy Gold = Gold版を購入(&G) Control Mapping... = キーマッピング(入力ボタン設定)(&O)... Debugging = デバッグ(&D) @@ -138,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = 逆アセンブル(&D)... Discord = Discord -Display Layout Editor = 画面のレイアウトを編集する... +Display Layout && Effects = 画面のレイアウトを編集する... Display Rotation = 画面の向き Dump Next Frame to Log = 次のフレームをログにダンプする(&U) Emulation = エミュレーション(&E) @@ -173,7 +172,7 @@ Log Console = ログコンソール(&L) Memory View... = メモリビュー(&V)... More Settings... = 詳細設定(&M)... Nearest = &Nearest -Non-Buffered Rendering = ノンバッファレンダリング (高速化)(&S) +Skip Buffer Effects = ノンバッファレンダリング (高速化)(&S) Off = オフ(&O) Open Chat = Open Chat Open Directory... = ディレクトリを開く(&D)... @@ -185,7 +184,6 @@ Pause = 一時停止(&P) Pause When Not Focused = 非フォーカス時は一時停止する(&P) Portrait = 縦 Portrait reversed = 縦 (反転) -Postprocessing Shader = 後処理シェーダ(&G) PPSSPP Forums = PPSSPPフォーラム(&F) Record = 記録(&R) Record Audio = オーディオを記録する(&A) @@ -233,7 +231,7 @@ DevMenu = 開発者用メニュー Disabled JIT functionality = 無効されたJIT機能 Draw Frametimes Graph = フレームタイムグラフを描く Dump Decrypted Eboot = 復号したEBOOT.BINを起動時にダンプする -Dump Frame GPU Commands = フレームGPUコマンドをダンプする +Dump next frame to log = 次のフレームをログにダンプする Enable driver bug workarounds = ドライバーバグの回避の有効化 Enable Logging = デバッグログを有効にする Enter address = アドレスを入力する @@ -242,11 +240,9 @@ Framedump tests = フレームダンプのテスト Frame Profiler = フレームプロファイラ GPU Driver Test = GPUドライバをテスト GPU Profile = GPUプロファイル -GPU Log Profiler = GPUログプロファイラ +GPU log profiler = GPUログプロファイラ Jit Compare = JIT 比較 JIT debug tools = JITデバッグツール -Language = 言語 -Load language ini = 言語のiniファイルをロードする Log Dropped Frame Statistics = ドロップしたフレームの統計を記録する Log Level = ログレベル Log View = ログビュー @@ -256,13 +252,12 @@ No block = ブロックなし Prev = 前へ Random = ランダム Replace textures = テクスチャを置き換える -Reset = Reset +Reset = リセット Reset limited logging = Reset limited logging RestoreDefaultSettings = 全ての設定 (キーの設定は除く) をデフォルトに戻しますか?\nやり直すことはできません。\n変更を反映させるにはPPSSPPを再起動してください。 RestoreGameDefaultSettings = ゲームの設定をPPSSPPのデフォルトに\n戻しますか? Resume = Resume Run CPU Tests = CPUテストを実行する -Save language ini = 言語のiniファイルをセーブする Save new textures = 新しいテクスチャを保存する Shader Viewer = シェーダビューワ Show Developer Menu = 開発者向けメニューを表示する @@ -289,10 +284,10 @@ Choose PPSSPP save folder = PPSSPPのセーブ用フォルダを選択する Confirm Overwrite = データを上書きしますか? Confirm Save = データをセーブしますか? ConfirmLoad = データをロードしますか? -ConnectingAP = Connecting to the access point.\nPlease wait... -ConnectingPleaseWait = Connecting.\nPlease wait... -ConnectionName = Connection name -Corrupted Data = Corrupted data +ConnectingAP = アクセスポイントに接続中.\nしばらくお待ちください... +ConnectingPleaseWait = 接続中.\nしばらくお待ちください... +ConnectionName = 接続名 +Corrupted Data = 破損したデータ Delete = 削除 Delete all = 全て削除 Delete completed = 削除が完了しました。 @@ -318,6 +313,8 @@ Load completed = ロードが完了しました。 Loading = ロード中です。\nしばらくお待ちください... LoadingFailed = データをロードできませんでした。 Move = 移動 +Move Down = 下へ移動 +Move Up = 上へ移動 Network Connection = ネットワーク接続 NEW DATA = 新しいデータ No = いいえ @@ -325,6 +322,7 @@ ObtainingIP = IPアドレスの取得中。 \nしばらくお待ちください. OK = OK Old savedata detected = 古いセーブデータを検出しました Options = オプション +Remove = 削除 Reset = リセット Resize = リサイズ Retry = リトライ @@ -332,10 +330,10 @@ Save = セーブ Save completed = セーブが完了しました。 Saving = セーブ中です。\nしばらくお待ちください... SavingFailed = データをセーブできませんでした。 -Search = Search -Select = Select -Shift = Shift -Skip = Skip +Search = 検索 +Select = セレクト +Shift = シフト +Skip = スキップ Snap = グリッドに吸着 Space = スペース SSID = SSID @@ -460,20 +458,19 @@ Aggressive = 最大限 Alternative Speed = カスタム速度1 (%で指定、0 = 無制限) Alternative Speed 2 = カスタム速度2 (%で指定、0 = 無制限) Anisotropic Filtering = 異方性フィルタリング +Antialiasing (MSAA) = アンチエイリアス (MSAA) +Aspect Ratio = アスペクト比 Auto = 自動 Auto (1:1) = 自動 (1:1) Auto (same as Rendering) = 自動 (レンダリング解像度と同じ) Auto FrameSkip = オートフレームスキップ -Auto Max Quality = Auto Max Quality +Auto Max Quality = 自動最高品質 Auto Scaling = 自動的に拡大 Backend = バックエンド Balanced = バランス Bicubic = Bicubic -BlockTransfer Tip = オンにしないと正しく表示できないゲームがいくつかあります -BlockTransferRequired = 警告: このゲームは「ブロック転送の効果をシミュレートする」をオンにする必要があります。 Both = 両方 Buffer graphics commands (faster, input lag) = グラフィックスコマンドをバッファする (高速, 入力ラグあり) -Buffered Rendering = バッファレンダリング BufferedRenderingRequired = 警告: このゲームは「レンダリングモード」を「バッファ」にする必要があります。 Camera = カメラの設定 Camera Device = カメラデバイスの選択 @@ -491,16 +488,16 @@ Device = デバイス Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 無効 -Display layout editor = 画面のレイアウトを編集する +Display Layout && Effects = 画面のレイアウトを編集する Display Resolution (HW scaler) = 画面解像度 (HWスケーラー) -Dump next frame to log = 次のフレームをログにダンプする Enable Cardboard VR = Cardboard VRを有効にする FPS = FPS Frame Rate Control = フレームレートのコントロール Frame Skipping = フレームスキップ Frame Skipping Type = フレームスキップのタイプ FullScreen = フルスクリーン -GPU log profiler = GPU log profiler +Geometry shader culling = ジオメトリシェーダーのカリング +GPUReadbackRequired = 警告: このゲームは"GPUリードバックのスキップ"をオフにする必要があります。 Hack Settings = ハックの設定 (不具合あり) Hardware Tessellation = ハードウェアテッセレーション Hardware Transform = ハードウェアトランスフォーム @@ -525,7 +522,7 @@ Must Restart = この変更を適用するにはPPSSPPを再起動してくだ Native device resolution = 機器のネイティブ解像度 Nearest = Nearest No buffer = バッファなし -Non-Buffered Rendering = ノンバッファレンダリング (高速化) +Skip Buffer Effects = ノンバッファレンダリング (高速化) None = なし Number of Frames = フレーム数 Off = オフ @@ -534,28 +531,27 @@ Overlay Information = オーバーレイ表示 Partial Stretch = 部分的に拡大 Percent of FPS = FPS中のパーセント Performance = パフォーマンス -Postprocessing effect = 後処理エフェクト -Postprocessing Shader = 後処理シェーダ -Recreate Activity = Recreate activity +Postprocessing shaders = 後処理シェーダ +Recreate Activity = アクティビティを再作成する Render duplicate frames to 60hz = フレームを複製して60Hzでレンダリングする RenderDuplicateFrames Tip = フレームレートが低いゲームでフレームレートをよりスムーズにできます Rendering Mode = レンダリングモード Rendering Resolution = レンダリング解像度 RenderingMode NonBuffered Tip = 高速ですが何も表示されなくなるゲームがあるかもしれません -Retain changed textures = 変更したテクスチャを保持する (低速化する場合がある) -RetainChangedTextures Tip = 多くのゲームが低速化しますが、かなり速くなるゲームもあります Rotation = 向き Safe = セーフ -Screen layout = 画面のレイアウト Screen Scaling Filter = 画像スケーリングのフィルタ Show Debug Statistics = デバッグ情報を表示する Show FPS Counter = FPSを表示する -Simulate Block Transfer = ブロック転送の効果をシミュレートする +Skip GPU Readbacks = GPUリードバックのスキップ Software Rendering = ソフトウェアレンダリング (実験的) Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します Speed = 速度 -Stretching = 拡大 +Speed Hacks = Speed Hacks (不具合あり) +Stereo display shader = ステレオディスプレイシェーダー +Stereo rendering = ステレオレンダリング +Stretch = 拡大 Texture Filter = テクスチャフィルタ Texture Filtering = テクスチャフィルタリング Texture Scaling = テクスチャスケーリング @@ -628,7 +624,7 @@ Audio = オーディオ Controls = コントロール Graphics = グラフィックス Networking = ネットワーク -Search = Search +Search = 検索 System = システム Tools = ツール @@ -718,7 +714,7 @@ Wlan = WLAN [Networking] AdHoc Server = アドホックサーバ AdhocServer Failed to Bind Port = アドホックサーバーがポートのバインドに失敗しました -AM: Data from Unknown Port = AM: Data from Unknown Port +AM: Data from Unknown Port = AM: 不明なポートからのデータ Auto = 自動 Bottom Center = 下中央 Bottom Left = 左下 @@ -727,12 +723,12 @@ Center Left = 左中央 Center Right = 右中央 Change Mac Address = MACアドレスを変更する Change proAdhocServer Address = PROアドホックサーバのIPアドレスを変更する (localhost = multiple instances) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = 新しいMACアドレスを生成しますか? +ChangeMacSaveWarning = いくつかのゲームのセーブデータはMACアドレスを照合します。一致しない場合データが使用不可、または破損する場合があります。 Chat = チャット Chat Button Position = チャットボタンの位置 Chat Here = ここにチャットを入力する -Chat message = Chat message +Chat message = チャットメーッセージ Chat Screen Position = チャット画面の位置 Disconnected from AdhocServer = アドホックサーバーから切断する DNS Error Resolving = DNSエラーの解決 @@ -752,13 +748,13 @@ Failed to Bind Localhost IP = ローカルホストIPのバインドに失敗し Failed to Bind Port = ポートのバインドに失敗しました Failed to connect to Adhoc Server = アドホックサーバーに接続できませんでした Forced First Connect = 強制初期接続 (より速い接続) -GM: Data from Unknown Port = GM: Data from Unknown Port -Hostname = Hostname +GM: Data from Unknown Port = GM: 不明なポートからのデータ +Hostname = ホストネーム Invalid IP or hostname = 無効なIPまたはホスト名 Minimum Timeout = 最小タイムアウト (低遅延をオーバーライド、単位ms) Misc = その他 (デフォルト = PSP互換) Network Initialized = ネットワークを初期化 -None = None +None = 無し Please change your Port Offset = ポートオフセットを変更してください Port offset = ポートオフセット (0 = PSP互換) Open PPSSPP Multiplayer Wiki Page = PPSSPPのアドホック接続Wikiページを開く (英語) @@ -799,9 +795,9 @@ Undo last save = セーブ内容を戻す [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -811,22 +807,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = オフ Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -875,24 +874,24 @@ website = ウェブサイトはこちら: written = 速度と移植性を保つためにC++で書かれています [MemStick] -Already contains PSP data = Already contains PSP data -Current = Current +Already contains PSP data = 既にPSPデータが存在しています。 +Current = 現在の DataWillStay = 保存データはPPSSPPをアンインストールしても残る。 DataCanBeShared = 通常版/ゴールド間でのデータの共有が可能。 DataCannotBeShared = 通常版/ゴールド間でのデータの共有が「できない」。 -Done! = Done! +Done! = 完了! EasyUSBAccess = PCとのUSB接続でフォルダにアクセスが簡単にできる。 -Failed to move some files! = Failed to move some files! -Failed to save config = Failed to save config -Free space = Free space -Manually specify PSP folder = Manually specify PSP folder -Move Data = Move Data -No data will be changed = No data will be changed -PPSSPP will restart after the change = PPSSPP will restart after the change -Selected PSP Data Folder = Selected PSP Data Folder -Skip for now = Skip for now -Starting move... = Starting move... -That folder doesn't work as a memstick folder. = That folder doesn't work as a memstick folder. +Failed to move some files! = いくつかのファイルの移動に失敗しました! +Failed to save config = セーブコンフィグに失敗しました! +Free space = 空き容量 +Manually specify PSP folder = PSPフォルダーを手動で設定する +Move Data = データ移動 +No data will be changed = データに変更はありません +PPSSPP will restart after the change = PPSSPPは変更後に再起動します +Selected PSP Data Folder = 選択されたPSPフォルダー +Skip for now = 今はスキップする +Starting move... = 移動開始... +That folder doesn't work as a memstick folder. = そのフォルダーはメモリースティックフォルダーとしては使用できません。 USBAccessThrough = USB接続は Android/data/org.ppsspp.ppsspp/files を通して行う。 USBAccessThroughGold = USB接続は Android/data/org.ppsspp.ppssppgold/files を通して行う。 DataWillBeLostOnUninstall = 警告! PPSSPPをアンインストールすると保存データも削除されます! @@ -900,8 +899,8 @@ MemoryStickDescription = PSPデータの保存先の選択(メモリースティ Create or Choose a PSP folder = フォルダの新規作成または既存フォルダの選択 Use App Private Data = アプリのプライベートフォルダに保存 Use PSP folder at root of storage = デバイスの内部ストレージのルートに保存 -Welcome to PPSSPP! = Welcome to PPSSPP! -WhatsThis = What's this? +Welcome to PPSSPP! = ようこそPPSSPPへ! +WhatsThis = What's This?! [RemoteISO] Browse Games = ゲームをブラウズする @@ -1008,11 +1007,11 @@ State load undone = ステートロードが取り消されました。 Untitled PSP game = 無題のPSPゲーム [Search] -No settings matched '%1' = No settings matched '%1' -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -Filter = Filter -Clear filter = Clear filter +No settings matched '%1' = この検索ワードにマッチするものはありませんでした '%1' +Filtering settings by '%1' = この検索ワードに設定しました '%1' +Find settings = メニュー内の設定項目の検索 +Filter = 検索する文字(ここをクリック) +Clear filter = 検索文字のクリア [Store] Already Installed = インストール済み @@ -1025,8 +1024,10 @@ Size = サイズ Uninstall = アンインストールする [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (1コアあたり %d, コア数 %d) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (未検出) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = CPU名 D3DCompiler Version = D3DCompilerバージョン Debug = デバッグ Debugger Present = デバッガーあり +Depth buffer format = Depth buffer format Device Info = デバイス情報 Directories = ディレクトリ Display Color Formats = Display Color Formats @@ -1097,6 +1099,8 @@ Change CPU Clock = CPUクロックを変更する (不安定) Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = 言語 Memory Stick folder = メモリースティックフォルダを変更する Memory Stick size = メモリースティックの容量の変更 (GB) Change Nickname = ニックネームを変更する @@ -1220,3 +1224,17 @@ Details = Details Dismiss = 無視 Download = ダウンロード New version of PPSSPP available = 新しいバージョンのPPSSPPを利用できます + +[VR] +% of native FoV = ネイティブ視野角(FoV)の % +6DoF movement = 6DoF動作 +Distance to 2D menus and scenes = 2Dメニューと空間までの距離 +Field of view scale = 視野角のスケール +Force 72Hz update = 72Hzに強制的に更新 +Heads-up display scale = ヘッドアップディスプレイスケール +Map controller movements to keys = コントローラーの動きをキーにマッピングする +Motion needed to generate action = アクションを生成するために必要なモーション +Stereoscopic vision (Experimental) = 立体映像 (実験的機能) +Virtual reality = バーチャルリアリティー +VR camera = VRカメラ +VR controllers = VRコントローラー diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 016ae0e857..db13726e6b 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Yakuwi Rendering Buy Gold = Tuku &Gold Control Mapping... = Pemetaan Kontrol ... Debugging = Debu&g @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = Mbucal Frame Sabanjure kanggo Mlebu Emulation = &Emulasi @@ -173,7 +172,7 @@ Log Console = &Konsol Log Memory View... = Tampilan &Memory... More Settings... = Setelan sing luwih ... Nearest = &Nearest -Non-Buffered Rendering = Skip efek buffer (ora yakuwi,luwih cepet) +Skip Buffer Effects = Skip efek buffer (ora yakuwi,luwih cepet) Off = &Mati Open Chat = Open Chat Open Directory... = Mbukak &Direktori... @@ -185,7 +184,6 @@ Pause = &Ngaso Pause When Not Focused = &Ngaso Nalika Ora Fokus Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Ngatifke Shader PPSSPP Forums = &Forum PPSSPP Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Mbucal EBOOT.BIN decrypted ing boot dolanan -Dump Frame GPU Commands = Mbucal printah pigura GPU +Dump next frame to log = Mbucal pigura jejere log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ngatifke ngangkut barang Enter address = Ketik alamat @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Pigura Profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit mbandhingake JIT debug tools = JIT debug tools -Language = Basa -Load language ini = Mbukak file basa Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Tingkat Log Log View = Tampilan Log @@ -262,7 +258,6 @@ RestoreDefaultSettings = Apa panjenengan yakin arep mulihake kabeh setelan bali RestoreGameDefaultSettings = Apa panjenengan yakin arep mulihake setelan-game tartamtu back kanggo awal PPSSPP? Resume = Resume Run CPU Tests = Mbukak Tes CPU -Save language ini = Simpen berkas basa Save new textures = Save new textures Shader Viewer = Tampilan shader Show Developer Menu = Tampilno menu pengembang @@ -318,6 +313,8 @@ Load completed = Mbukak rampung. Loading = Mbukak\nMohon nteni... LoadingFailed = Ora biso mbukak data. Move = Pindahno +Move Down = Move Down +Move Up = Move Up Network Connection = Koneksi Jaringan NEW DATA = DATA ANYAR No = Ora @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = He.eh Old savedata detected = Simpenan lawas terdeteksi Options = Opsi +Remove = Remove Reset = Ngreset Resize = Ubah Ukuran Retry = Jajal Maning @@ -460,6 +458,8 @@ Aggressive = Agresif Alternative Speed = Kacepetan Alternatif Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Penyaring Anisotropis +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Otomatis Auto (1:1) = Otomatis (1:1) Auto (same as Rendering) = Otomatis (padha Rendering) @@ -469,11 +469,8 @@ Auto Scaling = Njongko Otomatis Backend = Backend Balanced = Imbang Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Kelorone Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Yakuwi Rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Tata letak Tampilan editor +Display Layout && Effects = Tata letak Tampilan editor Display Resolution (HW scaler) = Resolusi tampilan (HW scaler) -Dump next frame to log = Mbucal pigura jejere log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Kontrol Frame-rate Frame Skipping = Frame-skip Frame Skipping Type = Frame skipping type FullScreen = Layar Penuh -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Retas setelsn (nyebabake glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Ndandani Hardware @@ -525,7 +522,7 @@ Must Restart = Wiwiti maneh PPSSPP kanggo aplikasi setelan. Native device resolution = Resolusi piranti asal Nearest = Cedhak No buffer = No buffer -Non-Buffered Rendering = Skip efek buffer (non-yakuwi,luwih cepet) +Skip Buffer Effects = Skip efek buffer (non-yakuwi,luwih cepet) None = Ora ana Number of Frames = Number of frames Off = Pateni @@ -534,28 +531,27 @@ Overlay Information = Informasi numpuki Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Kinerja -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Mode Rendering Rendering Resolution = Rendering résolusi RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Makaryakke diganti tekstur (kadhangkala luwih alon) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotasi Safe = Aman -Screen layout = Screen layout Screen Scaling Filter = Layar njongko Filter Show Debug Statistics = Tampilno statistik debug Show FPS Counter = Tampilno penghitung FPS -Simulate Block Transfer = Simulasi efek transfer pemblokiran +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software rendering (jajalan) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Kacepetan -Stretching = Stretching +Speed Hacks = Speed Hacks (nyebabake glitches) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Penyaring Tekstur Texture Filtering = Penyaring Tekstur Texture Scaling = Skala Tekstur @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Kartun CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Keabu-abuan +GreenLevel = Green level Intensity = Intensity -InverseColors = Warna kebalik +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna Natural NaturalA = Natural Colors (no blur) Off = Ora Aktif Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Ukuran Uninstall = Copot [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Basa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Ganti Jeneng @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Ngilangi Download = Unduh New version of PPSSPP available = Versi anyar PPSSPP mpun ono monggo di comot + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index d08d55dd14..730edd76a8 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -129,7 +129,6 @@ Backend = 렌더링 백엔드(&B) (PPSSPP 재시작) Bicubic = 고등차수보간(&B) Break = 증딘 Break on Load = 불러오기 시 중단 -Buffered Rendering = 버퍼링된 렌더링(&B) Buy Gold = 골드 버전 구매(&G) Control Mapping... = 제어 맵핑(&O)... Debugging = 디버그(&D) @@ -138,7 +137,7 @@ Direct3D9 = Direct3D 9(&9) Direct3D11 = Direct3D 11(&1) Disassembly = 역어셈블리(&D)... Discord = 디스코드 -Display Layout Editor = 레이아웃 편집기 표시... +Display Layout && Effects = 레이아웃 편집기 표시... Display Rotation = 화면 회전 Dump Next Frame to Log = 로그에 다음 프레임 덤프(&U) Emulation = 에뮬레이션(&E) @@ -173,7 +172,7 @@ Log Console = 콘솔 로그(&L) Memory View... = 메모리 보기(&V)... More Settings... = 기타 설정(&M)... Nearest = 근접 필터링(&N) -Non-Buffered Rendering = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름)(&S) +Skip Buffer Effects = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름)(&S) Off = 끔(&O) Open Chat = 채팅 열기 Open Directory... = 디렉터리 열기(&D)... @@ -185,7 +184,6 @@ Pause = 일시 정지(&P) Pause When Not Focused = 포커싱되지 않았을 때 일시 정지(&P) Portrait = 세로방향 Portrait reversed = 세로방향 반전 -Postprocessing Shader = 후처리 셰이더(&G) PPSSPP Forums = PPSSPP 포럼(&F) Record = 녹음(&R) Record Audio = 사운드 녹음(&A) @@ -233,7 +231,7 @@ DevMenu = 개발메뉴 Disabled JIT functionality = 비활성화된 JIT 기능 Draw Frametimes Graph = 프레임 시간 그래프 그리기 Dump Decrypted Eboot = 게임 부팅 시 해독된 EBOOT.BIN 덤프 -Dump Frame GPU Commands = 덤프 프레임 GPU 명령 +Dump next frame to log = 다음 프레임을 로그로 덤프 Enable driver bug workarounds = 드라이버 버그 해결 방법 활성화 Enable Logging = 디버그 로깅 활성화 Enter address = 주소 입력 @@ -242,11 +240,9 @@ Framedump tests = 프레임 덤프 테스트 Frame Profiler = 프레임 프로파일러 GPU Driver Test = GPU 드라이버 테스트 GPU Profile = GPU 프로파일 -GPU Log Profiler = GPU 로그 프로파일러 +GPU log profiler = GPU 로그 프로파일러 Jit Compare = JIT 비교 JIT debug tools = JIT 디버그 도구 -Language = 언어 -Load language ini = 언어 ini 불러오기 Log Dropped Frame Statistics = 삭제된 프레임 통계 기록 Log Level = 로그 레벨 Log View = 로그 보기 @@ -262,7 +258,6 @@ RestoreDefaultSettings = 모든 설정을 기본값으로 되돌리겠습니까? RestoreGameDefaultSettings = 게임별 설정을\nPPSSPP 기본값으로 복원하겠습니까? Resume = 다시 시작 Run CPU Tests = CPU 테스트 실행 -Save language ini = 언어 ini 저장 Save new textures = 새로운 텍스처 저장 Shader Viewer = 셰이더 뷰어 Show Developer Menu = 개발자 메뉴 표시 @@ -318,6 +313,8 @@ Load completed = 불러오기가 완료되었습니다. Loading = 로딩 중\n잠시만 기다려 주세요... LoadingFailed = 데이터를 불러올 수 없습니다. Move = 이동 +Move Down = Move Down +Move Up = Move Up Network Connection = 네트워크 연결 NEW DATA = 새로운 데이터 No = 아니오 @@ -325,6 +322,7 @@ ObtainingIP = IP 주소를 가져오는 중입니다.\n잠시만 기다려 주 OK = 확인 Old savedata detected = 오래된 저장 데이터 감지됨 Options = 옵션 +Remove = Remove Reset = 재설정 Resize = 크기 조정 Retry = 재시도 @@ -460,6 +458,8 @@ Aggressive = 과격 Alternative Speed = 대체 속도 (%, 0 = 무제한) Alternative Speed 2 = 대체 속도 2 (%, 0 = 무제한) Anisotropic Filtering = 비등방성 필터링 +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = 자동 Auto (1:1) = 자동 (1:1) Auto (same as Rendering) = 자동 (렌더링 해상도와 동일) @@ -469,11 +469,8 @@ Auto Scaling = 자동 스케일링 Backend = 백엔드 Balanced = 평형 Bicubic = 고등차수보간 -BlockTransfer Tip = 일부 게임에서는 올바른 그래픽을 위해 이 기능을 켜야 합니다. -BlockTransferRequired = 경고: 이 게임은 "블록 전송 효과 시뮬레이션"을 켬으로 설정해야 합니다. Both = 둘 다 Buffer graphics commands (faster, input lag) = 버퍼 그래픽 명령 (빠름, 입력 지연) -Buffered Rendering = 버퍼링된 렌더링 BufferedRenderingRequired = 경고: 이 게임은 "렌더링 모드"를 "버퍼링"으로 설정해야 합니다. Camera = 카메라 Camera Device = 카메라 장치 @@ -491,15 +488,16 @@ Device = 장치 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 비활성화 -Display layout editor = 화면 레이아웃 편집기 +Display Layout && Effects = 화면 레이아웃 편집기 Display Resolution (HW scaler) = 화면 해상도(HW 스케일러) -Dump next frame to log = 다음 프레임을 로그로 덤프 Enable Cardboard VR = 카드보드 VR 활성화 FPS = FPS Frame Rate Control = 프레임속도 제어 Frame Skipping = 프레임 생략 Frame Skipping Type = 프레임 생략 유형 FullScreen = 전체화면 +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = 핵 설정 (결함을 일으킬 수 있음) Hardware Tessellation = 하드웨어 조각화 Hardware Transform = 하드웨어 변환 @@ -524,7 +522,7 @@ Must Restart = 이 변경 사항을 적용하려면 PPSSPP를 다시 시작해 Native device resolution = 기본 장치 해상도 Nearest = 근접 필터링 No buffer = 버퍼 없음 -Non-Buffered Rendering = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름) +Skip Buffer Effects = 버퍼 효과 건너뛰기(버퍼되지 않음, 더 빠름) None = 없음 Number of Frames = 프레임 수 Off = 끔 @@ -533,28 +531,27 @@ Overlay Information = 오버레이 정보 Partial Stretch = 부분 늘이기 Percent of FPS = FPS 비율 Performance = 성능 -Postprocessing effect = 후처리 효과 -Postprocessing Shader = 후처리 쉐이더 +Postprocessing shaders = 후처리 쉐이더 Recreate Activity = 활동 재생성 Render duplicate frames to 60hz = 중복 프레임을 60Hz로 렌더링 RenderDuplicateFrames Tip = 낮은 프레임 속도에서 실행되는 게임에서 프레임 속도를 더 부드럽게 만들 수 있습니다. Rendering Mode = 렌더링 모드 Rendering Resolution = 렌더링 해상도 RenderingMode NonBuffered Tip = 더 빠르지만 일부 게임에서는 아무 것도 표현되지 않을 수 있습니다. -Retain changed textures = 변경된 텍스처 유지 (때로는 느림) -RetainChangedTextures Tip = 많은 게임을 느리게 하지만 일부 게임은 훨씬 빠르게 만듭니다. Rotation = 회전 Safe = 안전 -Screen layout = 화면 레이아웃 Screen Scaling Filter = 화면 크기 조정 필터 Show Debug Statistics = 디버그 통계 표시 Show FPS Counter = FPS 카운터 표시 -Simulate Block Transfer = 블록 전송 효과 시뮬레이션 +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = 소프트웨어 렌더링 (느림) Software Skinning = 소프트웨어 스키닝 SoftwareSkinning Tip = 대부분의 게임에서 더 빠르게 CPU에서 스킨 모델 드로우를 결합합니다. Speed = 속도 -Stretching = 늘이기 +Speed Hacks = Speed Hacks (결함을 일으킬 수 있음) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = 늘이기 Texture Filter = 텍스처 필터링 Texture Filtering = 텍스처 필터링 Texture Scaling = 텍스처 스케일링 @@ -573,7 +570,6 @@ VSync = 수직 동기화 Vulkan = Vulkan Window Size = 창 크기 xBRZ = xBRZ 필터 -GPU log profiler = GPU 로그 프로파일러 [InstallZip] Delete ZIP file = ZIP 파일 삭제 @@ -799,9 +795,9 @@ Undo last save = 마지막 저장 실행 취소 [PostShaders] (duplicated setting, previous slider will be used) = (설정이 중복되면 이전 슬라이더가 사용됩니다.) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-색상 Amount = 양 Black border = 검정 테두리 @@ -809,21 +805,24 @@ Bloom = 블룸 Brightness = 밝기 Cartoon = 카툰 ColorCorrection = 색상 교정 +ColorPreservation = Color preservation Contrast = 명암 CRT = CRT 스캔라인 FXAA = FXAA 안티 에일리어싱 Gamma = 감마 -Grayscale = 그레이스케일 +GreenLevel = Green level Intensity = 강도 -InverseColors = 색 반전 +LCDPersistence = LCD Persistence Natural = 자연스러운 색상 NaturalA = 자연스러운 색상 (흐림 없음) Off = 끔 Power = 전원 PSPColor = PSP 색상 +RedBlue = Red/Blue glasses Saturation = 채도 Scanlines = 스캔라인 (CRT) Sharpen = 선명함 +SideBySide = Side by side (SBS) SSAA(Gauss) = 슈퍼샘플 AA (가우스) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1038,8 +1037,10 @@ Size = 크기 Uninstall = 제거 [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (코어 당 %d, 코어 %d 개) %d bytes = %d 바이트 +%d Hz = %d Hz (none detected) = (감지되지 않음) 3D API = 3D API ABI = ABI @@ -1057,6 +1058,7 @@ CPU Name = 이름 D3DCompiler Version = D3D컴파일러 버전 Debug = 디버그 Debugger Present = 디버거 탐지 +Depth buffer format = Depth buffer format Device Info = 장치 정보 Directories = 디렉토리 Display Information = 정보 표시 @@ -1107,6 +1109,8 @@ AVI Dump started. = AVI 덤프가 시작됨 AVI Dump stopped. = AVI 덤프가 중지됨 Cache ISO in RAM = RAM에 전체 ISO 캐시 Change CPU Clock = 에뮬레이트된 PSP의 CPU 클럭 변경 (불안정) +Game crashed = Game crashed +Language = 언어 Memory Stick folder = 메모리 스틱 폴더 Memory Stick size = 메모리 스틱 크기 Change Nickname = 별명 변경 @@ -1241,3 +1245,17 @@ Choices: = 선택: List: = 목록: Progress: %1% = 진행율: %1% Screen representation = 화면 표현 + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index dad15456b5..4b80bad664 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -129,7 +129,6 @@ Backend = &ການສະແດງຜົນທີ່ສະໜັບສະໜຸ Bicubic = &ປັບພາບແບບ Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = ການສະແດງຜົນແບບໃຊ້ ບັບເຟີ້ Buy Gold = & ຊື້ແບບ Gold Control Mapping... = &ແຜງຄວບຄຸມ... Debugging = &ແກ້ໄຂຈຸດບົກພ່ອງ @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = &Direct3D11 Disassembly = &ການແຍກອົງປະກອບ... Discord = Discord -Display Layout Editor = ແກ້ໄຂຮູບແບບສະແດງຜົນ... +Display Layout && Effects = ແກ້ໄຂຮູບແບບສະແດງຜົນ... Display Rotation = ການໝຸນໜ້າຈໍ Dump Next Frame to Log = &ດຶງຂໍ້ມູນຂອງເຟຣມຕໍ່ໄປເພື່ອເກັບບັນທຶກຄ່າ Emulation = &ການຈຳລອງ @@ -173,7 +172,7 @@ Log Console = &ເກັບຄ່າຄອນໂຊລ Memory View... = &ມຸມມອງຄ່າຄວາມຈຳ... More Settings... = &ການຕັ້ງຄ່າອື່ນໆ... Nearest = &ພາບເປັນຮອຍຍັກໄດ້ -Non-Buffered Rendering = &ຂ້າມການໃຊ້ເອັບເຟັກບັບເຟີ້ (ບໍ່ມີບັບເຟີ້, ໄວຂຶ້ນ) +Skip Buffer Effects = &ຂ້າມການໃຊ້ເອັບເຟັກບັບເຟີ້ (ບໍ່ມີບັບເຟີ້, ໄວຂຶ້ນ) Off = &ປິດ Open Chat = Open Chat Open Directory... = &ເປີດໄດເຣກທໍຣີ... @@ -185,7 +184,6 @@ Pause = &ຢຸດຊົ່ວຄາວ Pause When Not Focused = &ຢຸດຊົ່ວຄາວເມື່ອບໍ່ໄດ້ຫຼິ້ນ Portrait = ແນວຕັ້ງ Portrait reversed = ກັບດ້ານແນວຕັ້ງ -Postprocessing Shader = &ຂະບວນການເຮັດວຽກໄລ່ປັບເສດແສງສີ PPSSPP Forums = &ຟໍຣຳ PPSSPP Record = ການບັນທຶກ Record Audio = ບັນທຶກສຽງ @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = ດຶງໄຟລ໌ EBOOT.BIN ອອກມາເກັບໄວ້ເມື່ອເລີ່ມເກມ -Dump Frame GPU Commands = ດຶງຄ່າເຟຣມຄຳສັ່ງຂອງ GPU +Dump next frame to log = ດຶງຂໍ້ມູນຂອງເຟຣມຕໍ່ໄປເພື່ອເກັບບັນທຶກຄ່າ Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = ເປີດໃຊ້ງານ logging Enter address = ໃສ່ຄ່າທີ່ຢູ່ @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = ລາຍລະອຽດຂອງເຟຣມ GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = ພາສາ -Load language ini = ໂຫຼດໄຟລ໌ພາສາ (.ini) Log Dropped Frame Statistics = ເກັບຄ່າສະຖິຕິເຟຣມເຣດຕົກ Log Level = ເກັບຄ່າລະດັບ Log View = ເກັບຄ່າມຸມມອງ @@ -262,7 +258,6 @@ RestoreDefaultSettings = ເຈົ້າແນ່ໃຈຫຼືບໍ່ວ່ RestoreGameDefaultSettings = ເຈົ້າແນ່ໃຈຫຼືບໍ່ວ່າຕ້ອງການຄືນຄ່າການຕັ້ງຄ່າເກມໂດຍສະເພາະ\nກັບສູ່ຄ່າເລີ່ມຕົ້ນ PPSSPP ຫຼືບໍ່? Resume = Resume Run CPU Tests = ເອີ້ນໃຊ້ການທົດສອບ CPU -Save language ini = ບັນທຶກພາສາຂອງ ini Save new textures = ບັນທຶກພື້ນຜິວໃໝ່ Shader Viewer = ມຸມມອງການປັບໄລ່ເສດສີ Show Developer Menu = ສະແດງເມນູສຳລັບນັກພັດທະນາ @@ -318,6 +313,8 @@ Load completed = ໂຫຼດຂໍ້ມູນສຳເລັດ Loading = ກຳລັງໂຫຼດ\nກະລຸນາລໍຖ້າ... LoadingFailed = ບໍ່ສາມາດໂຫຼດຂໍ້ມູນ. Move = ເຄື່ອນຍ້າຍ +Move Down = Move Down +Move Up = Move Up Network Connection = ການເຊື່ອມຕໍ່ເຄື່ອຂ່າຍ NEW DATA = ຂໍ້ມູນໃໝ່ No = ບໍ່ແມ່ນ @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = ຕົກລົງ Old savedata detected = ກວດພົບຂໍ້ມູນເຊບເກົ່າ Options = ໂຕເລືອກ +Remove = Remove Reset = ຕັ້ງຄ່າໃໝ່ Resize = ປັບຂະໜາດ Retry = ລອງໃໝ່ອີກຄັ້ງ @@ -460,6 +458,8 @@ Aggressive = ຮຸນແຮງ Alternative Speed = ຄວາມໄວເສີມ (ໃນ %, 0 = ບໍ່ຈຳກັດ) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = ກຳຈັດຄວາມບໍ່ຄົມຊັດ +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = ອັດຕະໂນມັດ Auto (1:1) = ອັດຕະໂນມັດ (1:1) Auto (same as Rendering) = ອັດຕະໂນມັດ (ແບບດຽວກັບຄວາມລະອຽດການສະແດງຜົນ) @@ -469,11 +469,8 @@ Auto Scaling = ປັບຂະໜາດສເກລອັດຕະໂນມັ Backend = ການສະໜັບສະໜູນ Balanced = ສົມດຸນ Bicubic = Bicubic -BlockTransfer Tip = ບາງເກມຕ້ອງເປີດໃຊ້ງານເພື່ອການສະແດງຜົນທີ່ຖືກຕ້ອງ -BlockTransferRequired = ຄຳເຕືອນ: ເກມນີ້ຕ້ອງການໃຫ້ເປີດໂໝດ "ຈຳລອງຜົນປິດກັ້ນການສົ່ງຜ່ານຂໍ້ມູນເອັບເຟກ" ນຳ Both = ໃຊ້ທັງ FPS ແລະ Speed Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = ການສະແດງຜົນແບບໃຊ້ບັບເຟີ້ BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = ແກ້ໄຂຮູບແບບໜ້າຈໍ +Display Layout && Effects = ແກ້ໄຂຮູບແບບໜ້າຈໍ Display Resolution (HW scaler) = ຄວາມລະອຽດໜ້າຈໍ (ຕາມຮາດແວຣ໌) -Dump next frame to log = ດຶງຂໍ້ມູນຂອງເຟຣມຕໍ່ໄປເພື່ອເກັບບັນທຶກຄ່າ Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = ຄວບຄຸມເຟຣມເຣດ Frame Skipping = ຂ້າມເຟຣມ Frame Skipping Type = Frame skipping type FullScreen = ເຕັມໜ້າຈໍ -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = ການຕັ້ງຄ່າແຮັກ Hardware Tessellation = Hardware tessellation Hardware Transform = ໃຊ້ຮາດແວຣ໌ປະມວນຜົນ @@ -525,7 +522,7 @@ Must Restart = ເຈົ້າຄວນເລີ່ມ PPSSPP ໃໝ່ເພື Native device resolution = ຄ່າຄວາມລະອຽດດັ້ງເດີມຂອງອຸປະກອນ Nearest = Nearest No buffer = No buffer -Non-Buffered Rendering = ຂ້າມການໃຊ້ບັບເຟີເອັບເຟກ (ບໍ່ໃຊ້ບັບເຟີ, ໄວຂຶ້ນ) +Skip Buffer Effects = ຂ້າມການໃຊ້ບັບເຟີເອັບເຟກ (ບໍ່ໃຊ້ບັບເຟີ, ໄວຂຶ້ນ) None = ບໍ່ມີ Number of Frames = Number of frames Off = ປິດ @@ -534,28 +531,27 @@ Overlay Information = ການສະແດງຂໍ້ມູນຊ້ອນທ Partial Stretch = ແນວຕັ້ງດຶງເຕັມຈໍ Percent of FPS = Percent of FPS Performance = ປະສິດທິພາບ -Postprocessing effect = Postprocessing effects -Postprocessing Shader = ຂະບວນການເຮັດວຽກໄລ່ປັບເສດສີ +Postprocessing shaders = ຂະບວນການເຮັດວຽກໄລ່ປັບເສດສີ Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = ໂໝດການສະແດງຜົນ Rendering Resolution = ຄວາມລະອຽດຂອງການສະແດງຜົນ RenderingMode NonBuffered Tip = ໄວຂຶ້ນແທ້, ແຕ່ອາດມີອາການຈໍດຳໃນບາງເກມ -Retain changed textures = ຮັກສາການປ່ຽນແປງຂອງພື້ນຜິວ (ຊ້າບາງເທື່ອ) -RetainChangedTextures Tip = ບາງເກມໃຊ້ແລ້ວຄວາມໄວຫຼຸດລົງ ແຕ່ບາງເກມຄວາມໄວກໍເພີ່ມຂຶ້ນ Rotation = ໝຸນຈໍ Safe = ປອດໄພ -Screen layout = Screen layout Screen Scaling Filter = ໂຕຕອງປັບສເກລໜ້າຈໍ Show Debug Statistics = ສະແດງຄ່າທາງສະຖິຕິການແກ້ໄຂຈຸດບົກພ່ອງ Show FPS Counter = ສະແດງຄ່າເຟຣມເຣດ ແລະ ຄວາມໄວ/ວິນາທີ -Simulate Block Transfer = ຈຳລອງຜົນປິດກັ້ນການສົ່ງຜ່ານຂໍ້ມູນເອັບເຟກ +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = ໃຊ້ຊອບແວຣ໌ສະແດງຜົນ (ລຸ້ນທົດລອງ) Software Skinning = ຊ໋ອບແວຣ໌ສກິນນິງ SoftwareSkinning Tip = ປະສານໂມເດລພື້ນຜິວໃຫ້ຂຽນຜ່ານ CPU, ເກມສ່ວນໃຫຍ່ໃຊ້ແລ້ວໄວຂຶ້ນ Speed = ຄວາມໄວ -Stretching = ດຶງເຕັມຈໍ +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = ດຶງເຕັມຈໍ Texture Filter = ໂຕຕອງພື້ນຜິວ Texture Filtering = ຕອງພື້ນຜິວ Texture Scaling = ປັບພື້ນຜິວ @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT FXAA = FXAA Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = InverseColors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural NaturalA = Natural Colors (no blur) Off = ປິດ Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = ຂະໜາດ Uninstall = ຖອນການຕິດຕັ້ງ [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = ພາສາ Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = ປ່ຽນຊື່ຫຼິ້ນ @@ -1220,3 +1224,17 @@ Details = Details Dismiss = ຍົກເລີກ Download = ດາວໂຫຼດ New version of PPSSPP available = ເວີຊັ່ນໃໝ່ຂອງ PPSSPP ພ້ອມໃຫ້ໂຫຼດແລ້ວ! + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 917e171242..61c035ec75 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Nusipirkti &Gold Control Mapping... = Va&ldymo mygtukų keitimas... Debugging = &Ekspermentas @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = "&Ardyti..." Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = "R&ašyti" kitą kadrą į "statusą" Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = "&Statuso" konsolė Memory View... = Atminties &rodymas... More Settings... = &Daugiau parametrų... Nearest = &Arčiausias -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Išjungti Open Chat = Open Chat Open Directory... = Atidaryti &vietą... @@ -185,7 +184,6 @@ Pause = &Pauzė Pause When Not Focused = &Stabdyti kai nefokusuota Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forumai Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = "Rašyti" atrakintą "EBOOT.BIN" failą žaidimui kraunantis -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = "Rašyti" kitą kadrą į statusą Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Įjungti testinio režimo statuso rašymą į failus Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Kalba -Load language ini = Krauti kalbos .ini failą Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Ar atstatyti "PPSSPP" parametrus į numatytuosius?\nVal RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Atidaryti pagrindinio procesoriaus testus -Save language ini = Išsaugoti kalbos .ini failą Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Rodyti kūrėjų meniu @@ -318,6 +313,8 @@ Load completed = Krovimas baigtas. Loading = Kraunama\nPrašome palaukti... LoadingFailed = Neįmanoma krauti duomenų. Move = Perkelti +Move Down = Move Down +Move Up = Move Up Network Connection = Interneto tinklas NEW DATA = NAUJI DUOMENYS No = Ne @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Gerai Old savedata detected = Aptikti seniau išsaugoti duomenys Options = Options +Remove = Remove Reset = Perkrauti Resize = Perkeisti dydį Retry = Pabandyti dar kartą @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Alternatyvus greitis (procentais, 0 procentų = neribotas) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = "Anisotropic" filtravimas +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatinis Auto (1:1) = Automatinė (1:1) Auto (same as Rendering) = Automatinis (kaip Rodymo rezoliucija) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = "Bicubic" -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Abu Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buferinis rodymas BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Ekrano rezoliucija ("HW" ištiesinimas) -Dump next frame to log = "Rašyti" kitą kadrą į statusą Enable Cardboard VR = Enable Cardboard VR FPS = Kadrai per sekundę Frame Rate Control = Kadrų kontrolė Frame Skipping = Kadrų praleidimas Frame Skipping Type = Frame skipping type FullScreen = Pilnas ekranas -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Modifikavimo parametrai (gali sukelti problemų) Hardware Tessellation = Hardware tessellation Hardware Transform = Aparatūros transformacija @@ -525,7 +522,7 @@ Must Restart = Jūs turite perkrauti "PPSSPP" programą, kad pakeisti parametrai Native device resolution = Įrenginio rezoliucija Nearest = Arčiausias No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Nieko Number of Frames = Number of frames Off = Išjungti @@ -534,28 +531,27 @@ Overlay Information = Užkadrinė informacija Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Greitis -Postprocessing effect = Postprocessing effects -Postprocessing Shader = "Įdėjiniminio" krovimo "šešėliai" (FX) +Postprocessing shaders = "Įdėjiniminio" krovimo "šešėliai" (FX) Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rodymo režimas Rendering Resolution = Rodymo rezoliucija RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Rodyti testinio režimo statistikas Show FPS Counter = Rodyti kadrų per sekundę rodmenis -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Programinės įrangos rodymas(ekspermentalus) Software Skinning = Programinės įrangos "nulupimas" SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Greitis -Stretching = Stretching +Speed Hacks = Speed Hacks (gali sukelti problemų) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Tekstūrų filtravimas Texture Filtering = Tekstūrų filtravimas Texture Scaling = Tekstūrų skalė @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Spalva Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Animacinis filmas CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT skenavimo linjos FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Perkeisti spalvas +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturalios spalvos NaturalA = Natural Colors (no blur) Off = Išjungti Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = CRT skenavimo linjos Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Dydis Uninstall = Išinstaliuoti [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Kalba Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Pakeisti slapyvardį @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Atmesti Download = Parsisiūsti New version of PPSSPP available = Galima nauja "PPSSPP" versija + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 5a6687e035..b97cfcc78a 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bikubik Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Beli ve&rsi Gold Control Mapping... = P&emetaan kawalan... Debugging = &Pepijat @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Pasangkan... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Putaran skrin Dump Next Frame to Log = L&etak frame berikutnya ke log Emulation = &Emulasi @@ -173,7 +172,7 @@ Log Console = &Log Konsol Memory View... = Lihat &Memori... More Settings... = &Tetapan lanjutan... Nearest = &Terdekat -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Tutup Open Chat = Open Chat Open Directory... = Buka &Penyimpanan... @@ -185,7 +184,6 @@ Pause = &Jeda Pause When Not Focused = &Jeda ketika tidak difokus Portrait = Portrait Portrait reversed = Portrait songsang -Postprocessing Shader = Shader pasc&apemprosesan PPSSPP Forums = PPSSPP &Forum Record = &Rakam Record Audio = Rakam &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Fungsi JIT yang dilumpuhkan Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Letak frame berikutnya ke log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Upayakan log pepijat Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = Ujian driver GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = Alat pepijat JIT -Language = Bahasa -Load language ini = Muatkan bahasa ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Anda pasti menetapkan semua tetapan kecuali pemetaan ka RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Jalankan percubaan CPU -Save language ini = Simpan bahasa .ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Papar menu pembangun @@ -318,6 +313,8 @@ Load completed = Memuat selesai. Loading = Memuat\nSila tunggu... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = DATA BAHARU No = Tidak @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Mula semula Resize = Resize Retry = Cuba semula @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Kelajuan alternatif Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bikubik -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Keduanya Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Letak frame berikutnya ke log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Kawalan kadar Frame Frame Skipping = Pelompatan Frame Frame Skipping Type = Frame skipping type FullScreen = Skrin penuh -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Godam tetapan (mungkin menyebabkan gangguan) Hardware Tessellation = Hardware tessellation Hardware Transform = Penukaran Alatan @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Terdekat No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Tiada Number of Frames = Number of frames Off = Tutup @@ -534,28 +531,27 @@ Overlay Information = Maklumat pertindihan Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Prestasi -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Pascapemprosesan Shader +Postprocessing shaders = Pascapemprosesan Shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Mod rendering Rendering Resolution = Resolusi rendering RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Papar statistik pepijat Show FPS Counter = Papar penghitung FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Render perisian (eksperimen) Software Skinning = Pembalutan Perisian SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Laju -Stretching = Stretching +Speed Hacks = Speed Hacks (mungkin menyebabkan gangguan) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Penapis Tekstur Texture Filtering = Penapisan Tekstur Texture Scaling = Penskalaan Tekstur @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Warna AA Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Kartun CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Anti aliasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Terbalikkan warna +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Warna asli NaturalA = Natural Colors (no blur) Off = Tutup Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Ketajaman +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Saiz Uninstall = Nyahpasang [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Bahasa Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Tukar nama samaran @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Abaikan Download = Muat turun New version of PPSSPP available = Versi terbaru PPSSPP tersedia + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index ad38f550cb..c22080e159 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -129,7 +129,6 @@ Backend = &Renderbackend (herstart PPSSPP) Bicubic = &Bicubisch Break = Break Break on Load = Break on load -Buffered Rendering = &Gebufferde weergave Buy Gold = Gold &kopen Control Mapping... = Bestur&ing toewijzen... Debugging = &Fouten opsporen @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Demonteren... Discord = Discord -Display Layout Editor = Schermweergave aanpassen... +Display Layout && Effects = Schermweergave aanpassen... Display Rotation = Schermrotatie Dump Next Frame to Log = &Volgende frame in logboek plaatsen Emulation = &Emulatie @@ -173,7 +172,7 @@ Log Console = Logboek&console Memory View... = &Geheugenweergave... More Settings... = &Meer instellingen... Nearest = &Naaste buur -Non-Buffered Rendering = &Buffereffecten nalaten (niet-gebufferd, sneller) +Skip Buffer Effects = &Buffereffecten nalaten (niet-gebufferd, sneller) Off = &Uit Open Chat = Open Chat Open Directory... = &Map openen... @@ -185,7 +184,6 @@ Pause = &Pauzeren Pause When Not Focused = &Pauzeren wanneer venster inactief is Portrait = Portret Portrait reversed = Omgekeerd portret -Postprocessing Shader = &Nabewerkingsshader PPSSPP Forums = &PPSSPP-forum Record = Opnemen Record Audio = Audio opnemen @@ -233,7 +231,7 @@ DevMenu = Ontwikkelaarsmenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Gedecodeerde EBOOT.BIN opslaan tijdens starten -Dump Frame GPU Commands = FPU-commando's van frame opslaan +Dump next frame to log = Volgende frame in logboek plaatsen Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Foutlogboek inschakelen Enter address = Adres invoeren @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frameanalyse GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit vergelijken JIT debug tools = JIT debug tools -Language = Taal -Load language ini = Taal-ini laden Log Dropped Frame Statistics = Overgeslagen framestatistieken vastleggen Log Level = Logniveau Log View = Logboekoverzicht @@ -262,7 +258,6 @@ RestoreDefaultSettings = Weet u zeker dat u alle instellingen wilt herstellen\nn RestoreGameDefaultSettings = Weet u zeker dat u de game-specifieke instellingen wilt\nherstellen naar de standaardwaarden van PPSSPP? Resume = Resume Run CPU Tests = CPU-controles uitvoeren -Save language ini = Taal-ini opslaan Save new textures = Nieuwe textures opslaan Shader Viewer = Shader weergeven Show Developer Menu = Ontwikkelaarsmenu weergeven @@ -318,6 +313,8 @@ Load completed = Het laden is voltooid. Loading = Bezig met laden...\nEen ogenblik geduld. LoadingFailed = Kan de data niet laden. Move = Slepen +Move Down = Move Down +Move Up = Move Up Network Connection = Netwerkverbinding NEW DATA = NIEUWE DATA No = Nee @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Oude savedata gedetecteerd Options = Opties +Remove = Remove Reset = Herstellen Resize = Schalen Retry = Opnieuw @@ -460,6 +458,8 @@ Aggressive = Agressief Alternative Speed = Alternatieve snelheid (in %, 0 = onbeperkt) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropische filter +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatisch Auto (1:1) = Automatisch (1:1) Auto (same as Rendering) = Auto (renderresolutie) @@ -469,11 +469,8 @@ Auto Scaling = Automatisch schalen Backend = Backend Balanced = Gebalanceerd Bicubic = Bicubisch -BlockTransfer Tip = Sommige games vereisen dat deze optie aan staat voor juiste graphics -BlockTransferRequired = Waarschuwing: Deze game vereist de optie Blokoverdrachteffecten simuleren. Both = Beide Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Gebufferde weergave BufferedRenderingRequired = Waarschuwing: Deze game vereist een "gebufferde renderingmodus". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Schermweergave bewerken +Display Layout && Effects = Schermweergave bewerken Display Resolution (HW scaler) = Schermresolutie (hardware) -Dump next frame to log = Volgende frame in logboek plaatsen Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerateinstellingen Frame Skipping = Frames overslaan Frame Skipping Type = Frame skipping type FullScreen = Volledig scherm -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hackinstellingen (kan glitches veroorzaken) Hardware Tessellation = Hardwarebetegeling Hardware Transform = Hardwaretransformatie @@ -525,7 +522,7 @@ Must Restart = U moet PPSSPP herstarten om de wijzigingen door te voeren. Native device resolution = Apparaatresolutie Nearest = Naaste buur No buffer = No buffer -Non-Buffered Rendering = Buffereffecten nalaten (niet-gebufferd, sneller) +Skip Buffer Effects = Buffereffecten nalaten (niet-gebufferd, sneller) None = Geen Number of Frames = Number of frames Off = Uit @@ -534,28 +531,27 @@ Overlay Information = Informatie op het scherm Partial Stretch = Gedeeltelijk uitrekken Percent of FPS = Percent of FPS Performance = Prestaties -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Nabewerkingsshader +Postprocessing shaders = Nabewerkingsshaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Weergavemodus Rendering Resolution = Renderresolutie RenderingMode NonBuffered Tip = Sneller, maar mogelijk wordt in sommige games niets gerenderd -Retain changed textures = Gewijzigde textures behouden (soms trager) -RetainChangedTextures Tip = Maakt vele games trager, maar sommige games veel sneller Rotation = Rotatie Safe = Veilig -Screen layout = Screen layout Screen Scaling Filter = Beeldschalingsfilter Show Debug Statistics = Foutopsporingsstatistieken weergeven Show FPS Counter = FPS-teller weergeven -Simulate Block Transfer = Blokoverdrachteffecten simuleren +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderen via software (experimenteel) Software Skinning = Skinning via software SoftwareSkinning Tip = Vermindert aantal renders en is sneller in games die de geavanceerde skinningtechniek gebruiken, maar voor sommige games trager Speed = Snelheid -Stretching = Uitrekken +Speed Hacks = Speed Hacks (kan glitches veroorzaken) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Uitrekken Texture Filter = Texturefilter Texture Filtering = Texturefilter Texture Scaling = Textures schalen @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-kleur Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT-scanlijnen FXAA = FXAA-antialiasing Gamma = Gamma -Grayscale = Grijswaarden +GreenLevel = Green level Intensity = Intensity -InverseColors = Omgekeerde kleuren +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natuurlijke kleuren NaturalA = Natural Colors (no blur) Off = Uit Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlijnen (CRT) Sharpen = Verscherpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Grootte Uninstall = Deïnstalleren [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (niets gedetecteerd) 3D API = 3D-API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Naam D3DCompiler Version = D3DCompiler version Debug = Fouten opsporen Debugger Present = Foutopsporing aanwezig +Depth buffer format = Depth buffer format Device Info = Apparaatinformatie Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Taal Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Gebruikersnaam wijzigen @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Annuleren Download = Downloaden New version of PPSSPP available = Er is een nieuwe versie van PPSSPP beschikbaar + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 70163c25c0..55c98402d6 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Debugloggning Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Language -Load language ini = Åpne språk-ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Kjør CPU-test -Save language ini = Lagre språk-ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = Ferdig lastet. Loading = Laster\nVent litt... LoadingFailed = Unable to load data. Move = Move +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = NEW DATA No = Nei @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Old savedata detected Options = Options +Remove = Remove Reset = Reset Resize = Resize Retry = Retry @@ -460,6 +458,8 @@ Aggressive = Aggressive Alternative Speed = Alternativ hastighet Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropisk filtrering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (same as rendering resolution) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balanced Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Begge Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffrad rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate control Frame Skipping = Ramme Hoppe over Frame Skipping Type = Frame skipping type FullScreen = Fullskjerm -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack settings (may cause glitches) Hardware Tessellation = Hardware tessellation Hardware Transform = Maskinvare omdanning @@ -525,7 +522,7 @@ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution Nearest = Nermest No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Ingen Number of Frames = Number of frames Off = Off @@ -534,28 +531,27 @@ Overlay Information = Overlay information Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Rendering mode Rendering Resolution = Rendering resolution RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen scaling filter Show Debug Statistics = Vis debugstatistik Show FPS Counter = Vis FPS-teller -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Programvare gjengivelse (eksperiment) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet -Stretching = Stretching +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Tekstur filtrering Texture Filtering = Tekstur filtrering Texture Scaling = Teksturskalning @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Gråtoneskala +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Language Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Endre Kallenavn @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Dismiss Download = Download New version of PPSSPP available = New version of PPSSPP available + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index e963535aee..b71c8075d6 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1,11 +1,11 @@ [Audio] -Alternate speed volume = Alternate speed volume +Alternate speed volume = Alternatywna prędkość emulacji Audio backend = Sterownik dźwięku (wymagany restart) Audio Error = Błąd Audio AudioBufferingForBluetooth = Bufory dźwięku dost. do Bluetooth (wolniejsze) Auto = Automatyczny Device = Urządzenie -Disabled = Wyłączone +Disabled = Wył. DSound (compatible) = DSound (kompatybilny) Enable Sound = Włącz dźwięk Global volume = Głośność globalna @@ -18,23 +18,23 @@ Use global volume = Używaj głośności globalnej WASAPI (fast) = WASAPI (szybki) [Controls] -Analog Binding = Analog Binding -Analog Limiter = Ogranicznik analoga -Analog Settings = Analog Settings -Analog Stick = Gałka analogowa -Analog Style = Analog Style -AnalogLimiter Tip = Jeśli "ogranicznik analoga" jest aktywny +Analog Binding = Powiązanie Analoga +Analog Limiter = Ogranicznik Analoga +Analog Settings = Ustawienia Analoga +Analog Stick = Gałka Analogowa +Analog Style = Styl Analoga +AnalogLimiter Tip = Jeśli "ogranicznik Analoga" jest aktywny Auto = Automatyczny -Auto-centering analog stick = Autocentrowanie gałki analogowej +Auto-centering analog stick = Autocentrowanie analoga Auto-hide buttons after seconds = Automatyczne ukrywanie przycisków po: Auto-rotation speed = Prędkość automatycznego obracania Auto-switch = Auto-switch -Base tilt position = Base tilt position -Binds = Binds -Button Binding = Button Binding +Base tilt position = Domyślna pozycja tytułu +Binds = Powiązania +Button Binding = Konfiguracja przycisków Button Opacity = Przeźroczystość przycisków Button style = Styl przycisków -Calibrate Analog Stick = Kalibracja Gałki Analogowej +Calibrate Analog Stick = Kalibracja Analoga Calibrate D-Pad = Kalibracja krzyżaka Calibrated = Skalibrowany Calibration = Kalibracja @@ -57,7 +57,7 @@ Gesture = Gesty Gesture mapping = Konfiguracja gestów Glowing borders = Świecące krawędzie HapticFeedback = Wibracje -Hide touch analog stick background circle = Hide touch analog stick background circle +Hide touch analog stick background circle = Ukryj obszar zasięgu Analoga Icon = Ikona Ignore gamepads when not focused = Ignoruj przyciski pada gdy okno nieaktywne Ignore Windows Key = Ignoruj klawisz Windows @@ -81,8 +81,8 @@ OnScreen = Przyciski ekranowe Portrait = Pionowo Portrait Reversed = Odwrócone pionowo PSP Action Buttons = Klawisze akcji PSP -Raw input = Raw input -Repeat mode = Repeat mode +Raw input = Zwykłe wejście +Repeat mode = Tryb powtarzania Reset to defaults = Domyślne Screen aligned to ground = Screen aligned to ground Screen at right angle to ground = Screen at right angle to ground @@ -106,7 +106,7 @@ Touch Control Visibility = Kontroler dotykowy (widoczny) Use custom right analog = Use custom right analog Use Mouse Control = Włącz kontrolę myszką Visibility = Widoczność -Visible = Visible +Visible = WIdoczny X = X Y = Y @@ -124,12 +124,11 @@ Refresh Rate = Szybkość odświeżania #Font = Trebuchet MS About PPSSPP... = O PPSSPP... Auto = Automatycznie -Auto Max Quality = Auto Max &Quality +Auto Max Quality = Automatyczna maksymalna &Jakość Backend = &Sterownik obrazu (Restartuje PPSSPP) Bicubic = Bicubic (Dwusześcienne) Break = Zatrzymaj Break on Load = Zatrzymaj po załadowaniu -Buffered Rendering = Renderowanie buforowe Buy Gold = Kup wersję Gold Control Mapping... = Ustawienia przycisków... Debugging = &Debugowanie @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = Dezasembluj... Discord = Discord -Display Layout Editor = Edytor położenia obrazu... +Display Layout && Effects = Edytor położenia obrazu... Display Rotation = Obracanie ekranu Dump Next Frame to Log = Zrzuć następną klatkę do dziennika zdarzeń Emulation = &Emulacja @@ -154,7 +153,7 @@ Game Settings = &Ustawienia gry GE Debugger... = Debugger GE... GitHub = Git&Hub Hardware Transform = &Transformacja sprzętowa -Help = Pomo&c +Help = Pomoc Hybrid = Hybrydowe Hybrid + Bicubic = Hybrydowe + Bicubic Ignore Illegal Reads/Writes = Ignoruj nieprawidłowe odczyty/zapisy @@ -173,7 +172,7 @@ Log Console = Konsola dziennika zdarzeń Memory View... = Podgląd pamięci... More Settings... = Więcej ustawień... Nearest = Najbliższe -Non-Buffered Rendering = &Nie renderuj efektów z bufora (niebuforowane, szybsze) +Skip Buffer Effects = &Nie renderuj efektów z bufora (niebuforowane, szybsze) Off = Wyłącz Open Chat = Otwórz Chat Open Directory... = Otwórz katalog... @@ -185,7 +184,6 @@ Pause = Pauza Pause When Not Focused = Pauzuj, gdy okno nieaktywne Portrait = Pionowo Portrait reversed = Odwrócone pionowo -Postprocessing Shader = Efekty wizualne shaderów PPSSPP Forums = Forum PPSSPP Record = &Nagrywaj Record Audio = Nagrywaj &dźwięk @@ -225,7 +223,7 @@ Allow remote debugger = Zezwól na zdalne debugowanie Backspace = Backspace Block address = Adres bloku By Address = Po adresie -Copy savestates to memstick root = Copy save states to Memory Stick root +Copy savestates to memstick root = Skopiuj zapisane stany do folderu głównego Karty Pamięci Create/Open textures.ini file for current game = Stwórz/otwórz plik textures.ini z bieżącej gry Current = Obecny Dev Tools = Narzędzia Developerskie @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Wyłącz funkcje JIT Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Zachowuj odszyfrowany EBOOT.BIN przy starcie -Dump Frame GPU Commands = Zrzuć klatkę komend GPU +Dump next frame to log = Zrzuć następną klatkę do dziennika zdarzeń Enable driver bug workarounds = Uruchom obejścia błędów sterownika Enable Logging = Włącz dziennik zdarzeń debugera Enter address = Wprowadź adres @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Profiler klatki GPU Driver Test = Test sterownika GPU -GPU Log Profiler = Profilowanie logów GPU +GPU log profiler = Profilowanie logów GPU GPU Profile = Profil GPU Jit Compare = Porównywanie JIT JIT debug tools = Narzędzia debugowania JIT -Language = Język -Load language ini = Wczytaj plik ini języka Log Dropped Frame Statistics = Loguj statystyki pominiętych klatek Log Level = Poziom dziennika zdarzeń Log View = Pokaż dziennik zdarzeń @@ -262,7 +258,6 @@ RestoreDefaultSettings = Czy na pewno chcesz przywrócić domyślne ustawienia?\ RestoreGameDefaultSettings = Czy na pewno chcesz przywrócić ustawienia specyficzne dla danych gier\npowrót do ustawień domyślnych PPSSPP? Resume = Wznów Run CPU Tests = Uruchom testy CPU -Save language ini = Zapisz plik ini języka Save new textures = Zapisz nową teksturę Shader Viewer = Podgląd Shaderów Show Developer Menu = Pokaż przycisk menu dewelopera @@ -318,6 +313,8 @@ Load completed = Ładowanie zakończone. Loading = Ładowanie\nProszę czekać... LoadingFailed = Nie można wczytać danych. Move = Przenieś +Move Down = Move Down +Move Up = Move Up Network Connection = Połączenie sieciowe NEW DATA = NOWE DANE No = Nie @@ -325,6 +322,7 @@ ObtainingIP = Uzyskiwanie adresu IP.\nProszę czekać... OK = OK Old savedata detected = Wykryto stary zapis gry Options = Opcje +Remove = Remove Reset = Resetuj Resize = Przeskaluj Retry = Spróbuj ponownie @@ -364,30 +362,30 @@ Disk full while writing data = Dysk zapełniony. ELF file truncated - can't load = ELF file truncated - can't load Error loading file = Wystąpił błąd: Error reading file = Błąd podczas odczytywania pliku. -Failed initializing CPU/Memory = Failed initializing CPU or memory -Failed to load executable: = Failed to load executable: +Failed initializing CPU/Memory = Nie można zainicjować CPU lub pamięci +Failed to load executable: = Nie udało się uruchomić pliku wykonywalnego: File corrupt = Uszkodzony plik Game disc read error - ISO corrupt = Nie można odczytać danych z dysku - plik ISO uszkodzony. -GenericAllStartupError = PPSSPP failed to start up with any graphics backend. Try upgrading your graphics and other drivers. -GenericBackendSwitchCrash = PPSSPP crashed while starting.\n\nThis usually means a graphics driver problem. Try upgrading your graphics drivers.\n\nGraphics backend has been switched: +GenericAllStartupError = PPSSPP nie może uruchomić żadnego trybu grafiki. Spróbuj zaktualizować swoje sterowniki do karty graficznej (oraz pozostałe). +GenericBackendSwitchCrash = PPSSPP - wystąpił błąd podczas uruchamiania emulatora.\n\nMoże to oznaczać problem ze sterownikiem do karty graficznej. Spróbuj go zaktualizować.\n\nSilnik graficzny został zmieniony: GenericDirect3D9Error = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej i biblioteki DirectX9.\n\nCzy chcesz zmienić sterownik na OpenGL?\n\nKomunikat błędu: GenericGraphicsError = Błąd grafiki GenericOpenGLError = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej.\n\nCzy chcesz zmienić sterownik na DirectX 9?\n\nKomunikat błędu: GenericVulkanError = Błąd inicjalizacji grafiki. Spróbuj zaktualizować sterowniki karty graficznej.\n\nCzy chcesz zmienić sterownik na OpenGL?\n\nKomunikat błędu: InsufficientOpenGLDriver = Wykryto brak obsługi wystarczająco nowej wersji OpenGL!\n\nTwoja karta graficzna zgłasza, że nie obsługuje OpenGL 2.0, który jest aktualnie wymagany do uruchomienia PPSSPP.\n\nSprawdź, czy Twoja karta graficzna jest zgodna z OpenGL 2.0. Jeśli jest, musisz zainstalować nowe sterowniki ze strony producenta.\n\nOdwiedź forum https://forums.ppsspp.org, aby uzyskać więcej informacji. Just a directory. = Tylko katalog. -Missing key = Missing key -MsgErrorCode = Error code: -MsgErrorSavedataDataBroken = Save data was corrupt. -MsgErrorSavedataMSFull = Memory Stick full. Check your storage space. -MsgErrorSavedataNoData = Warning: no save data was found. -MsgErrorSavedataNoMS = Memory Stick not inserted. +Missing key = Brak klucza +MsgErrorCode = Kod błędu: +MsgErrorSavedataDataBroken = Uszkodzone dane zapisu. +MsgErrorSavedataMSFull = Karta pamięci pełna. Sprawdź miejsce na dysku. +MsgErrorSavedataNoData = Uwaga: nie znaleziono danych zapisu. +MsgErrorSavedataNoMS = Brak Karty Pamięci. No EBOOT.PBP, misidentified game = Brak EBOOT.PBP, gra nierozpoznana. Not a valid disc image. = Nieprawidłowy obraz nośnika. OpenGLDriverError = Błąd sterownika OpenGL. PPSSPP doesn't support UMD Music. = PPSSPP nie wspiera UMD Music. PPSSPP doesn't support UMD Video. = PPSSPP nie wspiera UMD Video. -PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP plays PSP games, not PlayStation 1 or 2 games. +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP odtwarza gry z PSP, a nie z PlayStation 1/2 PPSSPPDoesNotSupportInternet = PPSSPP aktualnie nie obsługuje połączenia z Internetem dla DLC, PSN oraz aktualizacji gier. PS1 EBOOTs are not supported by PPSSPP. = Pliki EBOOT PS1 nie są obsługiwane przez PPSSPP. PSX game image detected. = Plik jest obrazem MODE2. PPSSPP nie obsługuje gier z PS1. @@ -400,7 +398,7 @@ textures.ini filenames may not be cross-platform = Nazwy plików w "textures.ini This is a saved state, not a game. = To jest zapis stanu, a nie gra. This is save data, not a game. = To jest zapis gry, a nie gra. Unable to create cheat file, disk may be full = Nie można utworzyć pliku kodów, dysk może być już zapełniony. -Unable to initialize rendering engine. = Unable to initialize rendering engine. +Unable to initialize rendering engine. = Nie można zainicjować silnika renderowania. Unable to write savedata, disk may be full = Nie można zapisać danych zapisu gry, dysk może być już zapełniony. Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = Ostrzeżenie: Pamięć wideo jest PEŁNA, nastąpi zmniejszenie rozdzielczości i zmiana na powolne buforowanie. Warning: Video memory FULL, switching to slow caching mode = Ostrzeżenie: Pamięć wideo jest PEŁNA, nastąpi zmiana na powolne buforowanie. @@ -427,7 +425,7 @@ Korea = Korea MB = MB One moment please... = Chwileczkę... Play = Graj -Remove From Recent = Usuń z "Ostatnio granych" +Remove From Recent = Usuń z "Ostatnio uruchamianych tytułów" SaveData = Zapisy gier Setting Background = Ustawianie tła Show In Folder = Pokaż w folderze @@ -460,6 +458,8 @@ Aggressive = Agresywne Alternative Speed = Alternatywna prędkość (w %, 0 = bez limitu) Alternative Speed 2 = Alternatywna prędkość 2 (w %, 0 = bez limitu) Anisotropic Filtering = Filtrowanie anizotropowe +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automatyczne Auto (1:1) = Automatyczna (1:1) Auto (same as Rendering) = Auto (jak roz. renderowania) @@ -469,14 +469,11 @@ Auto Scaling = Automatyczne skalowanie Backend = Sterownik graficzny Balanced = Zbalansowane Bicubic = Bicubic (Dwusześcienne) -BlockTransfer Tip = Niektóre gry wymagają włączenia tej opcji do poprawnego działania. -BlockTransferRequired = Uwaga: Ta gra wymaga włączonej opcji "Symuluj efekty transferu bloków". Both = Oba -Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Renderowanie buforowe +Buffer graphics commands (faster, input lag) = Bufor komand grafiki (szybsze, może powodować lagi sterowania) BufferedRenderingRequired = Uwaga: Ta gra wymaga włączonej opcji "Renderowanie buforowe". -Camera = Camera -Camera Device = Camera device +Camera = Kamera +Camera Device = Kamera Cardboard Screen Size = Rozmiar ekranu (% widocznego obszaru) Cardboard Screen X Shift = Przesunięcie X (% pustej przestrzeni) Cardboard Screen Y Shift = Przesunięcie Y (% pustej przestrzeni) @@ -491,16 +488,16 @@ Device = Urządzenie Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Wył. -Display layout editor = Edytor położenia obrazu +Display Layout && Effects = Edytor położenia obrazu Display Resolution (HW scaler) = Rozdzielczość ekranu (skaler sprz.) -Dump next frame to log = Zrzuć następną klatkę do dziennika zdarzeń -Enable Cardboard VR = Enable Cardboard VR +Enable Cardboard VR = Aktywuj Cardboard VR FPS = Tylko FPS Frame Rate Control = Kontrola klatek na sekundę Frame Skipping = Pomijanie klatek Frame Skipping Type = Tryb pomijania klatek FullScreen = Pełny ekran -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Ustawienia specjalne (powodują problemy) Hardware Tessellation = Sprzętowa teselacja Hardware Transform = Transformacja sprzętowa @@ -525,7 +522,7 @@ Must Restart = Musisz zrestartować PPSSPP, aby zobaczyć zmiany. Native device resolution = Natywna rozdzielczość urządzenia Nearest = Najbliższe No buffer = No buffer -Non-Buffered Rendering = Nie renderuj efektów z bufora (niebuforowane, szybsze) +Skip Buffer Effects = Nie renderuj efektów z bufora (niebuforowane, szybsze) None = Wył. Number of Frames = Ilość klatek Off = Wył. @@ -534,28 +531,27 @@ Overlay Information = Nakładka informacyjna Partial Stretch = Częściowe rozciągnięcie Percent of FPS = Procent FPS Performance = Wydajność -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Efekty wizualne shaderów +Postprocessing shaders = Efekty wizualne shaderów Recreate Activity = Recreate activity -Render duplicate frames to 60hz = Render duplicate frames to 60 Hz +Render duplicate frames to 60hz = Renderuj duplikowane klatki w 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Tryb renderowania Rendering Resolution = Rozdzielczość renderowania RenderingMode NonBuffered Tip = Szybsze, ale niektóre gry mogą się nie wyświetlać -Retain changed textures = Zachowuj zmienione tekstury (czasem wolniejsze) -RetainChangedTextures Tip = Spowalnia wiele gier, ale mocno przyspiesza kilka innych Rotation = Obrót Safe = Bezpieczne -Screen layout = Screen layout Screen Scaling Filter = Filtrowanie skalowania ekranu Show Debug Statistics = Pokaż statystyki debugowania Show FPS Counter = Pokaż licznik FPS -Simulate Block Transfer = Symuluj efekty transferu bloków +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderowanie programowe (wolne) Software Skinning = Programowy skinning SoftwareSkinning Tip = Łączy na CPU wywołania rysujące modele z animacjami, przyspieszenie w większości gier Speed = Prędkość (procentowo) -Stretching = Rozciąganie +Speed Hacks = Speed Hacks (powodują problemy) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Rozciąganie Texture Filter = Filtrowanie tekstur Texture Filtering = Filtrowanie tekstur Texture Scaling = Skalowanie tekstur @@ -615,7 +611,7 @@ Load = Otwórz... Loading... = Loading... PinPath = Przypnij PPSSPP can't load games or save right now = PPSSPP nie może teraz załadować gier ani zapisywać stanów -Recent = Ostatnio grane +Recent = Ostatnio uruchamiane SavesAreTemporary = PPSSPP zapisuje do pamięci tymczasowej SavesAreTemporaryGuidance = Wypakuj PPSSPP, by móc trwale zapisywać SavesAreTemporaryIgnore = Ignoruj @@ -685,7 +681,7 @@ Record = Record Remote hold = Remote hold Rewind = Przewiń do tyłu Right = Strzałka w prawo -Right Analog Stick = Right Analog Stick +Right Analog Stick = Prawa Gałka Analogowa RightAn.Down = Pr. gałk. w dół RightAn.Left = Pr. gałk. w lewo RightAn.Right = Pr. gałk. w prawo @@ -723,13 +719,13 @@ DataCanBeShared = Data can be shared between PPSSPP regular/Gold DataCannotBeShared = Data CANNOT be shared between PPSSPP regular/Gold! DataWillBeLostOnUninstall = Warning! Data will be lost when you uninstall PPSSPP! DataWillStay = Data will stay even if you uninstall PPSSPP. -Done! = Done! -EasyUSBAccess = Easy USB access +Done! = Ukończono! +EasyUSBAccess = Łatwy dostęþ do USB Failed to move some files! = Nie udało się przenieść niektórych plików! -Failed to save config = Failed to save config -Free space = Free space -Manually specify PSP folder = Manually specify PSP folder -MemoryStickDescription = Choose where to keep PSP data (Memory Stick) +Failed to save config = Nie udało się zapisać ustawień +Free space = Wolne miejsce +Manually specify PSP folder = Ustaw folder PSP ręcznie +MemoryStickDescription = Wybierz, gdzie chcesz umieścić dane PSP (Karta Pamięci) Move Data = Move Data Selected PSP Data Folder = Selected PSP Data Folder No data will be changed = No data will be changed @@ -759,38 +755,38 @@ Change proAdhocServer Address = Zmień adres IP serwera PRO dla trybu ad hoc (lo ChangeMacSaveConfirm = Generate a new MAC address? ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Chat -Chat Button Position = Chat button position -Chat Here = Chat here -Chat message = Chat message -Chat Screen Position = Chat screen position -Disconnected from AdhocServer = Disconnected from ad hoc server +Chat Button Position = Pozycja przycisku chatu +Chat Here = Napisz wiadomość +Chat message = Wiadomość +Chat Screen Position = Pozycja ekranu chatu +Disconnected from AdhocServer = Rozłączono z ad hoc serwerem DNS Error Resolving = DNS error resolving Enable built-in PRO Adhoc Server = Włącz wbudowany serwer PRO dla trybu ad hoc -Enable network chat = Enable network chat +Enable network chat = Uruchom chat Enable networking = Włącz sieć/WLAN (beta, może powodować błędy) -Enable UPnP = Enable UPnP (need a few seconds to detect) -EnableQuickChat = Enable quick chat +Enable UPnP = Uruchom UPnP (potrzebuje kilka sekund na wykrycie) +EnableQuickChat = Uruchom szybki chat Enter a new PSP nickname = Enter a new PSP nickname -Enter Quick Chat 1 = Enter quick chat 1 -Enter Quick Chat 2 = Enter quick chat 2 -Enter Quick Chat 3 = Enter quick chat 3 -Enter Quick Chat 4 = Enter quick chat 4 -Enter Quick Chat 5 = Enter quick chat 5 -Error = Error +Enter Quick Chat 1 = Wejdź na szybki chat 1 +Enter Quick Chat 2 = Wejdź na szybki chat 2 +Enter Quick Chat 3 = Wejdź na szybki chat 3 +Enter Quick Chat 4 = Wejdź na szybki chat 4 +Enter Quick Chat 5 = Wejdź na szybki chat 5 +Error = Błąd Failed to Bind Localhost IP = Failed to bind localhost IP Failed to Bind Port = Failed to bind port Failed to connect to Adhoc Server = Failed to connect to ad hoc server -Forced First Connect = Forced first connect (faster connect) +Forced First Connect = Wymuszenie pierwszego połączenie (szybsze łączenie) GM: Data from Unknown Port = GM: Data from Unknown Port Hostname = Hostname Invalid IP or hostname = Invalid IP or hostname -Minimum Timeout = Minimum timeout (override in ms, 0 = default) -Misc = Miscellaneous (default = PSP compatibility) +Minimum Timeout = Minimalny czas oczekiwania (podaj w ms, domyślnie 0) +Misc = Inne (domyślnie = Kompatybilność z PSP) Network Initialized = Sieć została zainicjowana None = None Please change your Port Offset = Please change your port offset Port offset = Zmień port (0 = zgodne z PSP) -Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page +Open PPSSPP Multiplayer Wiki Page = Przejdź do strony PPSSPP pomocy dla wielu graczy. proAdhocServer Address: = Ad hoc server address: Quick Chat 1 = Quick chat 1 Quick Chat 2 = Quick chat 2 @@ -803,12 +799,12 @@ Send Discord Presence information = Transmituj informacje Discord Rich Presence Top Center = Top center Top Left = Top left Top Right = Top right -Unable to find UPnP device = Unable to find UPnP device +Unable to find UPnP device = Nie udało się zlokalizować urządzenia UPnP UPnP (port-forwarding) = UPnP (port forwarding) UPnP need to be reinitialized = UPnP need to be reinitialized -UPnP use original port = UPnP use original port (enabled = PSP compatibility) -Validating address... = Validating address... -WLAN Channel = WLAN channel +UPnP use original port = UPnP używa oryginalnego portu (włączone = kompatybilność z PSP) +Validating address... = Uwierzytelnianie addresu... +WLAN Channel = Kanał WLAN You're in Offline Mode, go to lobby or online hall = You're in offline mode, go to lobby or online hall [Pause] @@ -816,21 +812,21 @@ Cheats = Kody Continue = Kontynuuj Create Game Config = Utwórz konfigurację gry Delete Game Config = Usuń konfigurację gry -Exit to menu = Wyjdź do menu +Exit to menu = Wróć do menu Game Settings = Ustawienia gry Load State = Wczytaj stan Rewind = Przewiń do tyłu Save State = Zapisz stan Settings = Ustawienia Switch UMD = Podmień UMD -Undo last load = Undo last load -Undo last save = Undo last save +Undo last load = Cofnij ostatnio wczytane +Undo last save = Cofnij ostatni zapis [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = Skalowanie 4×HQ -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Kolor AA Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Komiks CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = Imitacja monitora CRT FXAA = Wygładzanie FXAA Gamma = Gamma -Grayscale = Skala szarości +GreenLevel = Green level Intensity = Intensity -InverseColors = Odwrócenie kolorów +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Naturalne kolory NaturalA = Naturalne kolory (bez rozmycia) Off = Wyłącz Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Linie skanowania Sharpen = Wyostrzenie +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -951,8 +950,8 @@ Perfect = Perfekcyjnie Perfect Description = Bezbłędna emulacja w całej grze - super! Plays = Działa Plays Description = Całkowicie grywalna, jednak można napotkać niewielkie błędy -ReportButton = Raportuj -Show disc CRC = Show disc CRC +ReportButton = Zgłoś błąd +Show disc CRC = Pokaż sumę kontrolną (CRC) dysku Speed = Szybkość Submit Feedback = Wyślij raport SuggestionConfig = Sprawdź dobre konfiguracje w raportach na stronie. @@ -1008,11 +1007,11 @@ State load undone = State load undone Untitled PSP game = Untitled PSP game [Search] -Clear filter = Clear filter -Filter = Filter -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -No settings matched '%1' = No settings matched '%1' +Clear filter = Wyczyść frazę +Filter = Szukaj +Filtering settings by '%1' = Wyszukiwanie ustawień '%1' +Find settings = Szukaj ustawień +No settings matched '%1' = Brak wyników dla '%1' [Store] Already Installed = Zainstalowane @@ -1025,8 +1024,10 @@ Size = Rozmiar Uninstall = Odinstaluj [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d na rdzeń, %d rdzenie) %d bytes = %d bajtów +%d Hz = %d Hz (none detected) = (nie wykryto) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Nazwa D3DCompiler Version = Wersja D3DCompiler Debug = Debug Debugger Present = Debugger obecny +Depth buffer format = Depth buffer format Device Info = Inf. o urządzeniu Directories = Directories Display Color Formats = Display Color Formats @@ -1098,15 +1100,17 @@ Color Saturation = Color Saturation Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. -Floating symbols = Floating symbols +Floating symbols = Przepływ symboli +Game crashed = Gra uległa awarii +Language = Język Memory Stick folder = Zmień folder Karty Pamięci Memory Stick size = Rozmiar Karty Pamięci Change Nickname = Zmień pseudonim ChangingMemstickPath = Zapisy gier, zapisy stanu i inne dane nie zostaną skopiowane do tego folderu.\n\nZmienić ścieżkę do folderu Karty Pamięci? ChangingMemstickPathInvalid = Ta ścieżka nie może zostać użyta do zapisu plików Karty Pamięci. Cheats = Kody -Clear Recent = Clear "Recent" -Clear Recent Games List = Wyczyść listę ostatnio granych +Clear Recent = Wyczyść "Ostatni uruchamiane" +Clear Recent Games List = Wyczyść listę ostatnio uruchamianych Clear UI background = Przywróć tło interfejsu Confirmation Button = Przycisk potwierdzenia Date Format = Format daty @@ -1117,7 +1121,7 @@ Developer Tools = Narzędzia programistyczne Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid Display Homebrew on a grid = Display "Homebrew && Demos" on a grid -Display Recent on a grid = Display "Recent" on a grid +Display Recent on a grid = Wyświetlaj "Ostatnio Uruchamiane" w projekcji siatki Dynarec (JIT) = Dynarec (JIT) Emulation = Emulacja Enable Cheats = Włącz kody @@ -1149,12 +1153,12 @@ Not a PSP game = To nie jest gra PSP Off = Wył. Oldest Save = Najstarszy zapis Path does not exist! = Path does not exist! -PSP Memory Stick = PSP Memory Stick +PSP Memory Stick = Karta Pamięci PSP PSP Model = Model PSP PSP Settings = Ustawienia PSP PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = Recent games +Recent games = Ostatnio uruchamiane tytuły Record Audio = Nagrywaj dźwięk Record Display = Nagrywaj obraz Reset Recording on Save/Load State = Resetuj nagrywanie przy zapisie/wczytaniu stanu @@ -1167,7 +1171,7 @@ Savestate slot backups = Kopie zapasowe slota zapisu stanu Screenshots as PNG = Zapisuj zrzuty ekranu jako PNG Set UI background... = Zmień tło interfejsu... Show ID = Show ID -Show Memory Stick folder = Show Memory Stick folder +Show Memory Stick folder = Pokaż folder Karty Pamięci Show region flag = Show region flag Simulate UMD delays = Symuluj opóźnienia UMD Slot 1 = Slot 1 @@ -1181,7 +1185,7 @@ Theme = Motyw Time Format = Format czasu UI = Interfejs użytkownika UI background animation = Animacja tła -UI Sound = UI sound +UI Sound = Dźwięki interfejsu urzydkownika undo %c = backup %c USB = USB Use Lossless Video Codec (FFV1) = Używaj stratnego kodeka wideo (FFV1) @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Odrzuć Download = Pobierz New version of PPSSPP available = Dostępna jest nowa wersja PPSSPP! + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 6d5b63cdcf..016bad4ed5 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -149,22 +149,21 @@ Refresh Rate = Taxa de atualização About PPSSPP... = &Sobre o PPSSPP... Auto = &Auto Auto Max Quality = Auto-maximizar a &qualidade -Backend = Backend de &renderização (Reinicia o PPSSPP) +Backend = Backend da &renderização (Reinicia o PPSSPP) Bicubic = &Bi-cúbico Break = Parar Break on Load = Parar ao carregar -Buffered Rendering = &Renderização com buffer Buy Gold = Comprar &Gold Control Mapping... = M&apeamento dos controles... Debugging = &Debug Deposterize = &Deposterizar Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 -Disassembly = &Disassembly... +Disassembly = &Fazer Disassembly... Discord = Discord -Display Layout Editor = Exibir o editor do esquema... +Display Layout && Effects = Exibir esquema && efeitos... Display Rotation = Rotação da exibição -Dump Next Frame to Log = D&umpar o frame seguinte no log +Dump Next Frame to Log = D&umpar o frame seguinte no registro Emulation = &Emulação Enable Cheats = Ativar &trapaças Enable Sound = Ativar s&om @@ -189,7 +188,7 @@ Landscape reversed = Paisagem invertida Language... = Id&ioma... Linear = &Linear Load = &Carregar... -Load .sym File... = Carreg&ar arquivo .sym +Load .sym File... = Carreg&ar arquivo .sym... Load Map File... = Carregar &arquivo do mapa... Load State = C&arregar o state Load State File... = &Carregar arquivo do state... @@ -197,7 +196,7 @@ Log Console = &Console dos logs Memory View... = Visualização da &memória... More Settings... = &Mais configurações... Nearest = &Mais próximo -Non-Buffered Rendering = &Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = &Ignorar efeitos do buffer Off = &Desligado Open Chat = Abrir Bate-Papo Open Directory... = Abrir &diretório... @@ -209,7 +208,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar quando não focado Portrait = Retrato Portrait reversed = Retrato invertido -Postprocessing Shader = Shader de pós-processamento PPSSPP Forums = Fórums do &PPSSPP Record = &Gravar Record Audio = Gravar &áudio @@ -255,38 +253,35 @@ Current = Atual Dev Tools = Ferramentas de desenvolvimento DevMenu = Menu do DEV Disabled JIT functionality = Funcionalidade do JIT desativada -Draw Frametimes Graph = Desenhar gráfico dos tempos dos frames -Dump Decrypted Eboot = Dumpar EBOOT.BIN decriptado no boot do jogo -Dump Frame GPU Commands = Dumpar comandos dos frames da GPU +Draw Frametimes Graph = Desenhar o gráfico dos tempos dos frames +Dump Decrypted Eboot = Dumpar o EBOOT.BIN decriptado na inicialização do jogo +Dump next frame to log = Dumpar o frame seguinte no registro Enable driver bug workarounds = Ativar soluções alternativas pros bugs dos drivers -Enable Logging = Ativar log do debug +Enable Logging = Ativar o registro do debug Enter address = Inserir endereço FPU = FPU Framedump tests = Testes dos dumps dos frames Frame Profiler = Analista dos frames GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU -GPU Log Profiler = Criador do Perfil do Registro da GPU +GPU log profiler = Criador do perfil do registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de debug do JIT -Language = Idioma -Load language ini = Carregar o ini do idioma -Log Dropped Frame Statistics = Pôr no log as estátisticas da queda dos frames -Log Level = Nível do log -Log View = Visualização do log -Logging Channels = Canais do log +Log Dropped Frame Statistics = Pôr no registro as estátisticas da queda dos frames +Log Level = Nível do registro +Log View = Visualização do registro +Logging Channels = Canais do registro Next = Próximo No block = Nenhum bloco Prev = Anterior Random = Aleatório Replace textures = Substituir texturas Reset = Resetar -Reset limited logging = Resetar o log limitado +Reset limited logging = Resetar o registro limitado RestoreDefaultSettings = Você tem certeza que você quer restaurar todas as configurações de volta aos padrões delas?\nAs configurações do mapeamento dos controles não são mudadas.\nVocê não pode desfazer isto.\nPor favor reinicie o PPSSPP para as mudanças terem efeito. RestoreGameDefaultSettings = Você tem certeza que você quer restaurar as configurações específicas do jogo\nde volta para os padrões do PPSSPP? Resume = Resumo Run CPU Tests = Executar testes da CPU -Save language ini = Salvar o ini do idioma Save new textures = Salvar novas texturas Shader Viewer = Visualizador dos shaders Show Developer Menu = Mostrar menu do desenvolvedor @@ -342,6 +337,8 @@ Load completed = Carregamento completado. Loading = Carregando\nPor favor espere... LoadingFailed = Incapaz de carregar os dados. Move = Mover +Move Down = Move Down +Move Up = Move Up Network Connection = Conexão de rede NEW DATA = NOVOS DADOS No = Não @@ -349,6 +346,7 @@ ObtainingIP = Obtendo endereço de IP.\nPor favor espere... OK = Ok Old savedata detected = Dados antigos do save detectados Options = Opções +Remove = Remove Reset = Resetar Resize = Redimensionar Retry = Tentar de novo @@ -484,6 +482,8 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Velocidade alternativa 2 (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Proporção do Aspecto Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (a mesma que a da resolução de renderização) @@ -493,11 +493,9 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico -BlockTransfer Tip = Alguns jogos requerem que isto esteja Ligado pros gráficos estarem corretos -BlockTransferRequired = Aviso: Esse jogo requer que a "simulação dos efeitos de transferência dos blocos" esteja definida como Ligada. +GPUReadbackRequired = Aviso: Este jogo requer "Ignorar Leituras da GPU" pra ser configurado como Desligado. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos comandos dos gráficos (mais rápido, atraso na entrada dos dados) -Buffered Rendering = Renderização com buffer BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". Camera = Câmera Camera Device = Dispositivo de câmera @@ -506,7 +504,7 @@ Cardboard Screen X Shift = Deslocamento do X (em % do espaço vazio) Cardboard Screen Y Shift = Deslocamento do Y (em % do espaço vazio) Cardboard VR Settings = Configurações do Google VR Cardboard Cheats = Trapaças -CPU Core = Core da CPU +CPU Core = Núcleo da CPU Debugging = Debugging DefaultCPUClockRequired = Aviso: Este jogo requer que o clock da CPU esteja definido como padrão. Deposterize = Deposterizar @@ -515,15 +513,15 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display layout editor = Exibe o editor dos esquemas +Display Layout && Effects = Exibir esquema && efeitos Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) -Dump next frame to log = Dumpa o próximo frame no log Enable Cardboard VR = Ativa o VR Cardboard FPS = FPS Frame Rate Control = Controle da taxa dos frames Frame Skipping = Pulo dos frames Frame Skipping Type = Tipo de pulo dos frames FullScreen = Tela cheia +Geometry shader culling = Abate do shader da geometria Hack Settings = Configurações dos hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por hardware Hardware Transform = Transformação por hardware @@ -548,7 +546,7 @@ Must Restart = Você deve reiniciar o PPSSPP pra esta mudança ter efeito. Native device resolution = Resolução nativa do dispositivo Nearest = Mais próximo No buffer = Sem buffer -Non-Buffered Rendering = Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = Ignorar efeitos do buffer None = Nenhum Number of Frames = Número de frames Off = Desligado @@ -557,28 +555,27 @@ Overlay Information = Informações da sobreposição Partial Stretch = Esticamento parcial Percent of FPS = Porcentagem dos FPS Performance = Performance -Postprocessing effect = Efeitos de pós-processamento -Postprocessing Shader = Shader de pós-processamento +Postprocessing shaders = Shaders de pós-processamento Recreate Activity = Recriar atividade Render duplicate frames to 60hz = Renderizar frames duplicados a 60 Hz RenderDuplicateFrames Tip = Pode tornar a taxa dos frames mais suave em jogos que executam em taxas de frames menores Rendering Mode = Modo de renderização Rendering Resolution = Resolução da renderização RenderingMode NonBuffered Tip = Mais rápido, mas nada pode ser desenhado em alguns jogos -Retain changed textures = Reter texturas mudadas (as vezes mais lento) -RetainChangedTextures Tip = Torna muitos jogos mais lentos mas alguns jogos muito mais rápidos Rotation = Rotação Safe = Seguro -Screen layout = Esquema da tela Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas do debug Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efeitos de transferência dos blocos +Skip GPU Readbacks = Ignorar Leituras da GPU Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade -Stretching = Esticamento +Speed Hacks = Hacks de Velocidade (podem causar erros de renderização!) +Stereo display shader = Shader de exbição do estéreo +Stereo rendering = Renderização do estéreo +Stretch = Esticar Texture Filter = Filtragem das texturas Texture Filtering = Filtragem das texturas Texture Scaling = Dimensionamento das texturas @@ -592,12 +589,11 @@ Upscale Type = Tipo de ampliação UpscaleLevel Tip = Pesado pra CPU - alguns dimensionamentos podem ser atrasados pra evitar travamentos Use all displays = Usar todas as telas Vertex Cache = Cache do vértice -VertexCache Tip = Mais rápido, mas pode causar tremulação temporária +VertexCache Tip = Mais rápido mas pode causar tremulação temporária VSync = VSync Vulkan = Vulkan Window Size = Tamanho da janela xBRZ = xBRZ -GPU log profiler = Criador de perfil da GPU [InstallZip] Delete ZIP file = Apagar arquivo ZIP @@ -627,7 +623,7 @@ Browse = Procurar... Buy PPSSPP Gold = Comprar o PPSSPP Gold Choose folder = Escolher pasta Credits = Créditos -PPSSPP Homebrew Store = Armazém dos Homebrews do PPSSPP +PPSSPP Homebrew Store = Loja dos Homebrews do PPSSPP Exit = Sair Game Settings = Configurações Games = Jogos @@ -750,9 +746,9 @@ Bottom Right = A direita do rodapé Center Left = Centralizar a esquerda Center Right = Centralizar a direita Change Mac Address = Mudar o endereço do MAC +ChangeMacSaveConfirm = Gerar um novo endereço pro MAC? +ChangeMacSaveWarning = Alguns jogos verificam o endereço do MAC quando carregam os dados do save então isto pode quebrar os saves antigos. Change proAdhocServer Address = Mudar o endereço de IP do servidor Ad Hoc PRO (localhost = múltiplas instâncias) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = Bate-papo Chat Button Position = Posição do botão de bate-papo Chat Here = Bata-papo aqui @@ -823,9 +819,9 @@ Undo last save = Desfazer o último salvamento [PostShaders] (duplicated setting, previous slider will be used) = (Configuração duplicada, o slider anterior será usado) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Cores-do-AA Amount = Quantidade Black border = Borda preta @@ -833,21 +829,24 @@ Bloom = Bloom Brightness = Brilho Cartoon = Cartoon ColorCorrection = Correção das cores +ColorPreservation = Preservação das cores Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama -Grayscale = Tons de cinza +GreenLevel = Nível verde Intensity = Intensidade -InverseColors = Cores invertidas +LCDPersistence = LCD Persistence Natural = Cores naturais NaturalA = Cores naturais (sem borrão) Off = Desligado Power = Energia PSPColor = Cor do PSP +RedBlue = Óculos Vermelhos/Azuis Saturation = Saturação Scanlines = Scanlines (CRT) Sharpen = Aprimorado +SideBySide = Lado a lado (SBS) SSAA(Gauss) = Super-amostragem do AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1042,8 +1041,10 @@ Size = Tamanho Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (nenhum detectado) 3D API = API 3D ABI = ABI @@ -1061,6 +1062,7 @@ CPU Name = Nome D3DCompiler Version = Versão do compilador D3D Debug = Debug Debugger Present = Debugger presente +Depth buffer format = Depth buffer format Device Info = Informação do dispositivo Directories = Diretórios Display Information = Informação da tela @@ -1144,6 +1146,7 @@ Fast Memory = Memória rápida (instável) Floating symbols = Símbolos flutuantes Force real clock sync (slower, less lag) = Forçar sincronização com o relógio real (mais lento, menos atrasos) frames, 0:off = frames, 0 = Desligado +Game crashed = O jogo teve um crash Games list settings = Configurações da lista de jogos General = Geral Grid icon size = Tamanho do ícone da grade @@ -1154,6 +1157,7 @@ Increase size = Aumentar tamanho Interpreter = Interpretador IO timing method = Método de cronometragem da E/S IR Interpreter = Interpretador do IR +Language = Idioma Memory Stick Folder = Pasta do cartão de memória Memory Stick inserted = Cartão de memória inserido MHz, 0:default = MHz, 0 = padrão @@ -1246,3 +1250,17 @@ Choices: = Escolhas: List: = Lista: Progress: %1% = Progresso: %1% Screen representation = Representação da tela + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index b50d6f0d95..2d1561c7f3 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -153,7 +153,6 @@ Backend = API de &renderização (Reinicia o PPSSPP) Bicubic = &Bi-cúbico Break = Parar Break on Load = Parar ao carregar -Buffered Rendering = &Renderização com buffer Buy Gold = Comprar &Gold Control Mapping... = M&apeamento dos controlos... Debugging = &Depurar @@ -162,7 +161,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Exibir o editor de esquema... +Display Layout && Effects = Exibir o editor de esquema... Display Rotation = Rotação da exibição Dump Next Frame to Log = G&uardar o frame seguinte no Log Emulation = &Emulação @@ -197,7 +196,7 @@ Log Console = &Console dos Logs Memory View... = Visualização da &memória... More Settings... = &Mais Definições... Nearest = &Mais próximo -Non-Buffered Rendering = &Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = &Ignorar efeitos do buffer (sem buffer, mais rápido) Off = &Desligado Open Chat = Abrir Bate-Papo Open Directory... = Abrir &Diretório... @@ -209,7 +208,6 @@ Pause = &Pausar Pause When Not Focused = &Pausar quando não focado Portrait = Retrato Portrait reversed = Retrato invertido -Postprocessing Shader = Shader de Pós-Processamento PPSSPP Forums = Fórums do &PPSSPP Record = &Gravar Record Audio = Gravar &Áudio @@ -257,7 +255,7 @@ DevMenu = Menu de Desenvolvedor Disabled JIT functionality = Funcionalidade do JIT desabilitada Draw Frametimes Graph = Desenhar gráfico dos tempos dos quadros Dump Decrypted Eboot = Guardar EBOOT.BIN decriptado no boot do jogo -Dump Frame GPU Commands = Guardar comandos dos quadros da GPU +Dump next frame to log = Guardar o próximo frame no log Enable driver bug workarounds = Ativar soluções alternativas para erros dos Drivers Enable Logging = Ativar log do depurador Enter address = Inserir endereço @@ -266,11 +264,9 @@ Framedump tests = Testes dos dumps dos quadros Frame Profiler = Analista dos quadros GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU -GPU Log Profiler = Criador do Perfil do Registro da GPU +GPU log profiler = Criador do Perfil do Registro da GPU Jit Compare = Comparar JIT JIT debug tools = Ferramentas de depuração do JIT -Language = Idioma -Load language ini = Carregar o .ini do Idioma Log Dropped Frame Statistics = Guardar no log as estátisticas da queda dos quadros Log Level = Nível do log Log View = Visualização do log @@ -286,7 +282,6 @@ RestoreDefaultSettings = Tens a certeza que queres restaurar todas as Definiçõ RestoreGameDefaultSettings = Tens a certeza que queres restaurar as Definições específicas do jogo\nde volta para os padrões do PPSSPP? Resume = Resumir Run CPU Tests = Executar testes da CPU -Save language ini = Guardar o .ini do Idioma Save new textures = Guardar novas texturas Shader Viewer = Visualizador dos Shaders Show Developer Menu = Mostrar Menu de Desenvolvedor @@ -342,6 +337,8 @@ Load completed = Carregamento completado. Loading = Carregando\nPor favor espere... LoadingFailed = Incapaz de carregar os dados. Move = Mover +Move Down = Move Down +Move Up = Move Up Network Connection = Conexão de rede NEW DATA = NOVOS DADOS No = Não @@ -349,6 +346,7 @@ ObtainingIP = Obtendo o Endereço de IP.\nPor favor espere... OK = Ok Old savedata detected = Dados antigos do save detectados Options = Opções +Remove = Remove Reset = Reiniciar Resize = Redimensionar Retry = Tentar de novo @@ -484,6 +482,8 @@ Aggressive = Agressivo Alternative Speed = Velocidade alternativa (em %, 0 = ilimitada) Alternative Speed 2 = Segunda Velocidade alternativa (em %, 0 = ilimitada) Anisotropic Filtering = Filtragem anisotrópica +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automático Auto (1:1) = Automático (1:1) Auto (same as Rendering) = Auto (a mesma de que a da resolução de renderização) @@ -493,11 +493,8 @@ Auto Scaling = Auto-redimensionamento Backend = Backend Balanced = Balanceado Bicubic = Bi-cúbico -BlockTransfer Tip = Alguns jogos requerem que esta opção esteja habilitada para os gráficos estarem corretos. -BlockTransferRequired = Aviso: Este jogo requer que a "Simulação dos Efeitos de Transferência dos Blocos" esteja habilitada. Both = Ambos Buffer graphics commands (faster, input lag) = Buffer dos Comandos Gráficos (mais rápido, atraso na entrada dos dados) -Buffered Rendering = Renderização com Buffer BufferedRenderingRequired = Aviso: Este jogo requer que o "modo de renderização" esteja definido "com buffer". Camera = Câmera Camera Device = Dispositivo de câmera @@ -515,15 +512,16 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display layout editor = Mostrar o editor dos esquemas +Display Layout && Effects = Mostrar o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) -Dump next frame to log = Guardar o próximo frame no log Enable Cardboard VR = Ativar o VR Cardboard FPS = FPS (Quadros Por Segundo) Frame Rate Control = Controle da taxa dos quadros Frame Skipping = Pulo dos quadros Frame Skipping Type = Tipo de pulo dos quadros FullScreen = Tela Cheia +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Definições dos Hacks (pode causar erros gráficos) Hardware Tessellation = Tesselação por Hardware Hardware Transform = Transformação por Hardware @@ -548,7 +546,7 @@ Must Restart = Deverás reiniciar o PPSSPP para esta mudança ter efeito. Native device resolution = Resolução Nativa do Dispositivo Nearest = Mais próximo No buffer = Sem buffer -Non-Buffered Rendering = Ignorar efeitos do buffer (sem buffer, mais rápido) +Skip Buffer Effects = Ignorar efeitos do buffer (sem buffer, mais rápido) None = Nenhum Number of Frames = Número de quadros Off = Desligado @@ -557,28 +555,27 @@ Overlay Information = Informações da sobreposição Partial Stretch = Esticamento Parcial Percent of FPS = Percentagem dos FPS Performance = Performance -Postprocessing effect = Efeitos de Pós-Processamento -Postprocessing Shader = Shader de Pós-Processamento +Postprocessing shaders = Shaders de Pós-Processamento Recreate Activity = Recriar atividade Render duplicate frames to 60hz = Renderizar quadros duplicados a 60 Hz RenderDuplicateFrames Tip = Pode tornar a taxa dos quadros mais suave em jogos que executam em taxas de quadros menores Rendering Mode = Modo de renderização Rendering Resolution = Resolução da renderização RenderingMode NonBuffered Tip = Mais rápido, mas poderá não ser desenhado nada em alguns jogos -Retain changed textures = Reter texturas mudadas (as vezes mais lento) -RetainChangedTextures Tip = Torna muitos jogos mais lentos mas alguns jogos muito mais rápidos Rotation = Rotação Safe = Seguro -Screen layout = Esquema da tela Screen Scaling Filter = Filtro do dimensionamento da tela Show Debug Statistics = Mostrar estatísticas de depuração Show FPS Counter = Mostrar contador de FPS -Simulate Block Transfer = Simular efeitos de transferência dos blocos +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Renderização por software (lento) Software Skinning = Skinning via software SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos Speed = Velocidade -Stretching = Esticamento +Speed Hacks = Speed Hacks (pode causar erros gráficos) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Esticamento Texture Filter = Filtração das texturas Texture Filtering = Filtração das texturas Texture Scaling = Dimensionamento das texturas @@ -597,7 +594,6 @@ VSync = VSync Vulkan = Vulkan Window Size = Tamanho da janela xBRZ = xBRZ -GPU log profiler = Criador de perfil da GPU [InstallZip] Delete ZIP file = Eliminar ficheiro .zip @@ -823,9 +819,9 @@ Undo last save = Desfazer o último salvamento [PostShaders] (duplicated setting, previous slider will be used) = (Definição duplicada, o slider anterior será usado) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = Cores-do-AA Amount = Quantidade Black border = Borda preta @@ -833,21 +829,24 @@ Bloom = Bloom Brightness = Brilho Cartoon = Estilo Cartoon ColorCorrection = Correção das cores +ColorPreservation = Color preservation Contrast = Contraste CRT = Scanlines do CRT FXAA = Anti-aliasing do FXAA Gamma = Gama -Grayscale = Tons de cinza +GreenLevel = Green level Intensity = Intensidade -InverseColors = Cores invertidas +LCDPersistence = LCD Persistence Natural = Cores naturais NaturalA = Cores naturais (sem borrão) Off = Desligado Power = Energia PSPColor = Cor do PSP +RedBlue = Red/Blue glasses Saturation = Saturação Scanlines = Scanlines (CRT) Sharpen = Aprimorado +SideBySide = Side by side (SBS) SSAA(Gauss) = Super-amostragem do AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1042,8 +1041,10 @@ Size = Tamanho Uninstall = Desinstalar [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (nenhum detectado) 3D API = API 3D ABI = ABI @@ -1061,6 +1062,7 @@ CPU Name = Nome D3DCompiler Version = Versão do compilador D3D Debug = Debug Debugger Present = Depurador presente +Depth buffer format = Depth buffer format Device Info = Informação do dispositivo Directories = Diretórios Display Information = Informação da tela @@ -1112,6 +1114,8 @@ AVI Dump started. = Dump do AVI iniciado AVI Dump stopped. = Dump do AVI parado Cache ISO in RAM = Colocar a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) +Game crashed = Game crashed +Language = Idioma Memory Stick folder = Pasta do Cartão de Memória Memory Stick size = Tamanho do Cartão de Memória Change Nickname = Mudar Nome @@ -1246,3 +1250,17 @@ Choices: = Escolhas: List: = Lista: Progress: %1% = Progresso: %1% Screen representation = Representação da tela + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 0ec247f441..48341c5f18 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = &Buffered Rendering Buy Gold = Buy &Gold Control Mapping... = C&ontrol Mapping... Debugging = &Debug @@ -138,7 +137,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Display layout && effects... Display Rotation = Display rotation Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emulation @@ -173,7 +172,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skip buffer effects Off = &Off Open Chat = Open Chat Open Directory... = Open &Directory... @@ -185,7 +184,6 @@ Pause = &Pause Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP &Forums Record = &Record Record Audio = Record &audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = Dump next frame to log Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Enable debug logging Enter address = Enter address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Jit compare JIT debug tools = JIT debug tools -Language = Limbă -Load language ini = Deschide fişier ini limbă Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Log level Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Are you sure you want to restore all settings back to t RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Run CPU tests -Save language ini = Salvează fişier ini limbă Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu @@ -318,6 +313,8 @@ Load completed = Încărcare Completă Loading = Se încarcă\nAșteptați... LoadingFailed = Nu s-au putut încărca datele. Move = Mișcă +Move Down = Move Down +Move Up = Move Up Network Connection = Conexiune la rețea NEW DATA = DATE NOI No = Nu @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Date vechi salvate detectate Options = Options +Remove = Remove Reset = Resetare Resize = Modificare marime Retry = Reîncearcă @@ -460,6 +458,8 @@ Aggressive = Agresiv Alternative Speed = Viteză alternativă (în %, 0 = nelimitat) Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) Anisotropic Filtering = Filtru Anisotropic +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Automat Auto (1:1) = Automat (1:1) Auto (same as Rendering) = Automat (la fel ca rezoluția de afișare) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Mod intern Balanced = Balansat Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = Warning: This game requires "simulate block transfer effects" to be set to On. Both = Ambele Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Afișare cu stocare BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Rezoluție ecran (scalare HW) -Dump next frame to log = Dump next frame to log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Control rată de cadre Frame Skipping = Cadre Omise Frame Skipping Type = Frame skipping type FullScreen = Ecran intreg -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Setări trișare (pot cauza stricăciuni) Hardware Tessellation = Hardware tessellation Hardware Transform = Transformare pe Hardware @@ -525,7 +522,7 @@ Must Restart = Trebuie să resartezi PPSSPP pt. ca această schimbare să aibă Native device resolution = Rezoluție nativă dispozitiv Nearest = Apropiată No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects None = Fără Number of Frames = Number of frames Off = Oprit @@ -534,28 +531,27 @@ Overlay Information = Informație suprapusă Partial Stretch = Partial stretch Percent of FPS = Percent of FPS Performance = Performanță -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Shader postprocesare +Postprocessing shaders = Shaders postprocesare Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Mod Afișare Rendering Resolution = Rezoluție Afișare RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotation Safe = Sigur -Screen layout = Screen layout Screen Scaling Filter = Filtrul de scalare al ecranului Show Debug Statistics = Arată statistici de depanare Show FPS Counter = Arată FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Afișare cu sofware (experimental) Software Skinning = Skinning cu software SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Viteză -Stretching = Stretching +Speed Hacks = Speed Hacks (pot cauza stricăciuni) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Filtru texturi Texture Filtering = Filtrare texturi Texture Scaling = Scalare texturi @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Culori Inversate +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Culori Naturale NaturalA = Natural Colors (no blur) Off = Oprit Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Mărime Uninstall = Dezinstalare [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Limbă Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Schimbă nume @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Ignoră Download = Descarcă New version of PPSSPP available = Nouă versiune de PPSSPP disponibilă. + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 35b73386d5..7774899cc3 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -82,7 +82,7 @@ Portrait = Портретная Portrait Reversed = Портретная (перевернутая) PSP Action Buttons = Кнопки действий PSP Raw input = Прямой ввод -Repeat mode = Repeat mode +Repeat mode = Режим повтора Reset to defaults = По умолчанию Screen aligned to ground = Экран повёрнут к земле Screen at right angle to ground = Экран повёрнут под прямым углом к земле @@ -129,7 +129,6 @@ Backend = Бэкенд &рендеринга (нужен перезапуск) Bicubic = &Бикубическое Break = Остановить Break on Load = Остановить после загрузки -Buffered Rendering = &Буферированный рендеринг Buy Gold = Купить &Gold Control Mapping... = Назначение &кнопок... Debugging = &Отладка @@ -138,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = &Direct3D 11 Disassembly = &Дизассемблер... Discord = Discord -Display Layout Editor = Редактор расположения экрана... +Display Layout && Effects = Редактор расположения экрана... Display Rotation = Ориентация экрана Dump Next Frame to Log = Сохранить &кадр в логе Emulation = &Эмуляция @@ -173,7 +172,7 @@ Log Console = Консоль отладки Memory View... = Просмотрщик па&мяти... More Settings... = &Ещё настройки... Nearest = &Ближайший -Non-Buffered Rendering = &Пропускать эффекты (небуферированный, быстрее) +Skip Buffer Effects = &Пропускать эффекты (небуферированный, быстрее) Off = В&ыключено Open Chat = Открыть чат Open Directory... = Открыть &папку... @@ -185,7 +184,6 @@ Pause = &Пауза Pause When Not Focused = &Пауза, когда окно не в фокусе Portrait = Портретная Portrait reversed = Портретная (перевернутая) -Postprocessing Shader = &Постобработка (шейдер) PPSSPP Forums = &Форум PPSSPP Record = &Запись Record Audio = Запись &звука @@ -233,20 +231,18 @@ DevMenu = Меню разраб. Disabled JIT functionality = Отключение функционала JIT Draw Frametimes Graph = Отрисовывать график времени кадров Dump Decrypted Eboot = Дамп дешифрованного EBOOT.BIN при запуске -Dump Frame GPU Commands = Сохранить команды ГП для кадра -Enable driver bug workarounds = Включить обход багов драйвера +Dump next frame to log = Сохранить следующий кадр в логе +Enable driver bug workarounds = Включить обход ошибок драйвера Enable Logging = Включить отладочное логирование Enter address = Ввести адрес FPU = FPU Framedump tests = Тест дампов кадров Frame Profiler = Профайлер кадров GPU Driver Test = Проверка драйвера ГП -GPU Log Profiler = GPU Log Profiler +GPU log profiler = Профилировщик логов ГП GPU Profile = Профиль ГП Jit Compare = Сравнение с JIT JIT debug tools = Инструменты отладки JIT -Language = Язык -Load language ini = Загрузить языковой .ini файл Log Dropped Frame Statistics = Логировать статистику пропущенных кадров Log Level = Уровень отладки Log View = Отображение логов @@ -256,13 +252,12 @@ No block = Нет блока Prev = Предыдущий Random = Случайный Replace textures = Подменять текстуры -Reset = Reset +Reset = Сбросить Reset limited logging = Сбросить ограниченное логирование RestoreDefaultSettings = "Вы уверены, что хотите сбросить настройки\n(кроме управления) на стандартные?\nВы не сможете это отменить.\nПожалуйста, перезапустите PPSSPP после сброса." RestoreGameDefaultSettings = Вы уверены, что хотите вернуть все параметры игры к стандартным? Resume = Resume Run CPU Tests = Запустить тесты ЦП -Save language ini = Сохранить языковой .ini файл Save new textures = Сохранять новые текстуры Shader Viewer = Просмотрщик шейдеров Show Developer Menu = Показывать меню разработчика @@ -318,6 +313,8 @@ Load completed = Загрузка завершена Loading = Загрузка\nПожалуйста, подождите... LoadingFailed = Невозможно загрузить даные. Move = Положение +Move Down = Сдвинуть вверх +Move Up = Сдвинуть вниз Network Connection = Сетевое подключение NEW DATA = Новое сохранение No = Нет @@ -325,6 +322,7 @@ ObtainingIP = Получение IP-адреса.\nПожалуйста, под OK = OK Old savedata detected = Старый формат сохранений обнаружен Options = Опции +Remove = Удалить Reset = Сбросить Resize = Размер Retry = Снова @@ -351,7 +349,7 @@ Yes = Да Zoom = Масштаб [Error] -7z file detected (Require 7-Zip) = файл сжат (7z).\nПожалуйста распакуйте (воспользуйтесь 7-Zip). +7z file detected (Require 7-Zip) = Файл сжат (7z).\nПожалуйста, распакуйте (воспользуйтесь 7-Zip). A PSP game couldn't be found on the disc. = На диске не удалось найти игру для PSP. Cannot boot ELF located outside mountRoot. = Невозможно загрузить ELF, расположенный вне mountRoot. Could not save screenshot file = Не удалось сохранить скриншот. @@ -460,6 +458,8 @@ Aggressive = Принудительно Alternative Speed = Другая скорость (в %, 0 = без ограничений) Alternative Speed 2 = Другая скорость 2 (в %, 0 = без ограничений) Anisotropic Filtering = Анизотропная фильтрация +Antialiasing (MSAA) = Сглаживание (MSAA) +Aspect Ratio = Соотношение сторон Auto = Авто Auto (1:1) = Авто (1:1) Auto (same as Rendering) = Авто (как разрешение рендеринга) @@ -469,11 +469,8 @@ Auto Scaling = Автомасштаб Backend = Бэкенд Balanced = Сбалансированно Bicubic = Бикубический -BlockTransfer Tip = Требуется для корректной графики в некоторых играх -BlockTransferRequired = Предупреждение: для этой игры требуется включить "Симуляцию эффектов от передачи блоков" Both = Оба Buffer graphics commands (faster, input lag) = Команды буферированной графики (быстрее, задержка ввода) -Buffered Rendering = Буферированный рендеринг BufferedRenderingRequired = Предупреждение: для этой игры требуется буферированный режим рендеринга. Camera = Камера Camera Device = Устройство камеры @@ -491,17 +488,16 @@ Device = Устройство Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Отключено -Display layout editor = Редактор расположения экрана +Display Layout && Effects = Редактор расположения экрана Display Resolution (HW scaler) = Разрешение экрана (аппаратное) -Dump next frame to log = Сохранить следующий кадр в логе Enable Cardboard VR = Включить Cardboard VR -#Features = Возможности FPS = FPS Frame Rate Control = Управление частотой кадров Frame Skipping = Пропуск кадров Frame Skipping Type = Тип пропуска кадров FullScreen = Полноэкранный режим -GPU log profiler = GPU log profiler +Geometry shader culling = Вызов геометрических шейдеров +GPUReadbackRequired = Внимание: Для данной игры нужно отключить настройку "Пропускать чтение данных ГП". Hack Settings = Параметры хаков (могут вызывать глюки) Hardware Tessellation = Аппаратная тесселяция Hardware Transform = Аппаратное преобразование @@ -526,7 +522,7 @@ Must Restart = Вы должны перезапустить PPSSPP, чтобы Native device resolution = Разрешение устройства Nearest = Ближайший No buffer = Нет буфера -Non-Buffered Rendering = Пропускать эффекты (небуферированный) +Skip Buffer Effects = Пропускать эффекты (небуферированный) None = Выключено Number of Frames = Количество кадров Off = Выключено @@ -535,33 +531,32 @@ Overlay Information = Информация в оверлее Partial Stretch = Частичное растягивание Percent of FPS = Процент от FPS Performance = Производительность -Postprocessing effect = Эффекты постобработки -Postprocessing Shader = Постобработка (шейдер) +Postprocessing shaders = Постобработка (шейдер) Recreate Activity = Создать активность заново Render duplicate frames to 60hz = Рендеринг дублирующихся кадров до 60 Гц RenderDuplicateFrames Tip = Может сгладить частоту кадров в тех играх, где она низкая Rendering Mode = Режим рендеринга Rendering Resolution = Разрешение рендеринга RenderingMode NonBuffered Tip = Быстрее, но ничего не отображает в некоторых играх -Retain changed textures = Сохранять измененные текстуры (иногда медленнее) -RetainChangedTextures Tip = Делает много игр медленнее, но некоторые - намного быстрее Rotation = Ориентация Safe = Безопасно -Screen layout = Расположение экрана Screen Scaling Filter = Фильтр масштабирования экрана Show Debug Statistics = Отображать отладочную информацию Show FPS Counter = Показывать счетчик FPS -Simulate Block Transfer = Симулировать эффекты от передачи блоков +Skip GPU Readbacks = Пропускать чтение данных ГП Software Rendering = Программный рендеринг (медленно) Software Skinning = Программная заливка SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх Speed = Скорость -Stretching = Растягивание +Speed Hacks = Speed Hacks (могут вызывать глюки) +Stereo display shader = Шейдер стереодисплея +Stereo rendering = Стереорендеринг +Stretch = Растягивание Texture Filter = Текстурный фильтр Texture Filtering = Фильтрация текстур Texture Scaling = Масштабирование текстур Texture Shader = Текстурный шейдер -Turn off Hardware Tessellation - unsupported = Выключите "аппаратную тесселяцию": не поддерживается +Turn off Hardware Tessellation - unsupported = Выключите настройку "Аппаратная тесселяция": не поддерживается Unlimited = Без ограничений Up to 1 = До 1 Up to 2 = До 2 @@ -587,8 +582,8 @@ Zip archive corrupt = ZIP-архив повреждён Zip file does not contain PSP software = В ZIP-файле отсутсвует ПО для PSP [KeyMapping] -Autoconfigure = Авто конфиг -Autoconfigure for device = Авто конфиг для устройства +Autoconfigure = Автоконфиг +Autoconfigure for device = Автоконфиг для устройства Bind All = Настроить всё Clear All = Очистить все Default All = По умолчанию @@ -604,7 +599,7 @@ Browse = Обзор... Buy PPSSPP Gold = PPSSPP Gold Choose folder = Выберите папку Credits = Авторы -PPSSPP Homebrew Store = магазина хоумбрю PPSSPP +PPSSPP Homebrew Store = Магазин хоумбрю PPSSPP Exit = Выход Game Settings = Настройки Games = Игры @@ -661,10 +656,10 @@ D-pad left = D-pad влево D-pad right = D-pad вправо D-pad up = D-pad вверх DevMenu = Меню разраб. -Display Landscape = Display Landscape -Display Landscape Reversed = Display Landscape Reversed -Display Portrait = Display Portrait -Display Portrait Reversed = Display Portrait Reversed +Display Landscape = Альбомная ориентация +Display Landscape Reversed = Альбомная ориентация (перевернутая) +Display Portrait = Портретная ориентация +Display Portrait Reversed = Портретная ориентация (перевернутая) Double tap button = Двойное нажатие на кнопку Down = Вниз Dpad = Крестовина @@ -728,8 +723,8 @@ Center Left = В центре слева Center Right = В центре справа Change Mac Address = Изменить MAC-адрес Change proAdhocServer Address = Изменить IP-адрес ad-hoc сервера (localhost = множество экземпляров) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = Сгенерировать новый MAC-адрес? +ChangeMacSaveWarning = Некоторые игры проверяют MAC-адрес при загрузке сохранений, из-за этого старые сохранения могут быть испорчены. Chat = Чат Chat Button Position = Позиция кнопки чата Chat Here = Чат здесь @@ -753,7 +748,7 @@ Failed to Bind Localhost IP = Не удалось привязать адрес Failed to Bind Port = Не удалось привязать порт Failed to connect to Adhoc Server = Не удалось подключиться к ad-hoc серверу Forced First Connect = Принудительное первое подключение (быстрое подключение) -GM: Data from Unknown Port = GM: Данные от неизвестного порта +GM: Data from Unknown Port = GM: Данные с неизвестного порта Hostname = Имя хоста Invalid IP or hostname = Некорректный IP или имя хоста Minimum Timeout = Минимальный таймаут (задержка в мс, 0 = по умолчанию) @@ -762,7 +757,7 @@ Network Initialized = Сеть активирована None = Нет Please change your Port Offset = Пожалуйста, измените ваше смещение порта Port offset = Смещение порта (0 = совместимость с PSP) -Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page +Open PPSSPP Multiplayer Wiki Page = Открыть wiki-страницу мультиплеера PPSSPP proAdhocServer Address: = Адрес ad-hoc сервера: Quick Chat 1 = Быстрый чат 1 Quick Chat 2 = Быстрый чат 2 @@ -800,9 +795,9 @@ Undo last save = Отменить последнее сохранение [PostShaders] (duplicated setting, previous slider will be used) = (дублированная настройка, используется предыдущий ползунок) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = Апскейлер пиксель-арта 4xHQ +5xBR = Апскейлер пиксель-арта 5xBR +5xBR-lv2 = Апскейлер пиксель-арта 5xBR-lv2 AAColor = AA-цвета Amount = Размер Animation speed (0 -> disable) = Скорость анимации (0 -> disable) @@ -810,24 +805,27 @@ Black border = Черные рамки Bloom = Свечение Brightness = Яркость Cartoon = Мультипликация -CatmullRom = Бикубический (Catmull-Rom) Апскейлер +CatmullRom = Бикубический (Catmull-Rom) апскейлер ColorCorrection = Цветокоррекция +ColorPreservation = Сохранение цвета Contrast = Контрастность CRT = ЭЛТ-развертка FXAA = Сглаживание FXAA Gamma = Gamma -Grayscale = Оттенки серого +GreenLevel = Green level Intensity = Интенсивность -InverseColors = Инвертированные цвета -MitchellNetravali = Бикубический (Mitchell-Netravali) Апскейлер +LCDPersistence = Остаточное изображение ЖК-дисплея +MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер Natural = Естественные цвета NaturalA = Естественные цвета (без размытия) -Off = Выключена +Off = Выключено Power = Сила PSPColor = Цвета PSP +RedBlue = Красно-синие очки Saturation = Насыщенность Scanlines = Строки развертки (ЭЛТ) Sharpen = Резкость +SideBySide = Side by side (SBS) SSAA(Gauss) = SSAA (Гаусс) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1026,8 +1024,10 @@ Size = Размер Uninstall = Удалить [SysInfo] +%0.2f Hz = %0.2f Гц %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт +%d Hz = %d Гц (none detected) = (не обнаружено) 3D API = 3D API ABI = ABI @@ -1045,13 +1045,14 @@ CPU Name = Название D3DCompiler Version = Версия D3DCompiler Debug = Отладочная Debugger Present = Отладчик присутствует +Depth buffer format = Формат буфера глубины Device Info = Устройство Directories = Директории -Display Color Formats = Display Color Formats +Display Color Formats = Форматы цветов дисплея Display Information = Информация о дисплее -Driver bugs = Driver bugs +Driver bugs = Ошибки драйвера Driver Version = Версия драйвера -EGL Extensions = Расширенния EGL +EGL Extensions = Расширения EGL Frames per buffer = Кадров на буфер GPU Information = Информация о ГП High precision float range = Диапазон точных дробных чисел @@ -1059,12 +1060,12 @@ High precision int range = Диапазон точных целых чисел Lang/Region = Язык/регион Memory Page Size = Размер страницы памяти Native Resolution = Родное разрешение -No GPU driver bugs detected = Ошибок GPU драйвера не обнаружено +No GPU driver bugs detected = Ошибок драйвера ГП не обнаружено OGL Extensions = Расширения OGL OpenGL ES 2.0 Extensions = Расширения OpenGL ES 2.0 OpenGL ES 3.0 Extensions = Расширения OpenGL ES 3.0 OpenGL Extensions = Расширения OpenGL -Optimal frames per buffer = Оптимально фреймов на буфер +Optimal frames per buffer = Оптимально кадров на буфер Optimal sample rate = Оптимальная частота дискретизации OS Information = Информация об ОС PPSSPP build = Сборка PPSSPP @@ -1096,7 +1097,9 @@ AVI Dump stopped. = Дамп AVI остановлен Cache ISO in RAM = Кэшировать ISO в ОЗУ Change CPU Clock = Эмулируемая частота ЦП PSP (нестабильно) Color Saturation = Насыщенность -Color Tint = Оттенок Цвета +Color Tint = Оттенок цвета +Game crashed = Игра вылетела +Language = Язык Memory Stick folder = Изменить папку с картой памяти Memory Stick size = Изменить размер карты памяти (Гб) Change Nickname = Изменить ник @@ -1206,18 +1209,32 @@ Tex4xBRZ = Tex4xBRZ Default = По умолчанию [UI Elements] -%1 button = %1 button -%1 checkbox = %1 checkbox -%1 choice = %1 choice -%1 heading = %1 heading -%1 radio button = %1 radio button -%1 text field = %1 text field -Choices: = Choices: -List: = List: -Progress: %1% = Progress: %1% -Screen representation = Screen representation +%1 button = %1 кнопка +%1 checkbox = %1 чекбокс +%1 choice = %1 выбор +%1 heading = %1 указание +%1 radio button = %1 радиокнопка +%1 text field = %1 текстовое поле +Choices: = Выборы: +List: = Список: +Progress: %1% = Прогресс: %1% +Screen representation = Представление экрана [Upgrade] Details = Подробности Dismiss = Отклонить Download = Загрузить New version of PPSSPP available = Доступна новая версия PPSSPP + +[VR] +% of native FoV = % стандартного угла обзора +6DoF movement = Движение 6DoF +Distance to 2D menus and scenes = Расстояние до 2D-меню и сцен +Field of view scale = Масштаб угла обзора +Force 72Hz update = Принудительная частота обновления 72 Гц +Heads-up display scale = Масштаб HUD +Map controller movements to keys = Назначить движения контроллера на клавиши +Motion needed to generate action = Необходимо движение для создания действия +Stereoscopic vision (Experimental) = Стереоизображение (экспериментально) +Virtual reality = Виртуальная реальность +VR camera = Камера ВР +VR controllers = Контроллеры ВР diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index fbacbb1219..3ed2d4c3e8 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -1,7 +1,7 @@ [Audio] Alternate speed volume = Volym vid alternativ hastighet Audio backend = Uppspelningsteknik (ändring kräver omstart!) -Audio Error = Audio Error +Audio Error = Ljudfel AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Enhet @@ -9,7 +9,7 @@ Disabled = Disabled DSound (compatible) = DSound (kompatibel) Enable Sound = Ljud Global volume = Global volym -Microphone = Microphone +Microphone = Mikrofon Microphone Device = Mikrofon-enhet Mute = Tysta Reverb volume = Volym på reverb-effekt @@ -31,12 +31,12 @@ Auto-rotation speed = Auto-rotation speed Auto-switch = Auto-switch Base tilt position = Base tilt position Binds = Binds -Button Binding = Button Binding +Button Binding = Knapp-bindning Button Opacity = Knappgenomskinlighet Button style = Knappstil Calibrate Analog Stick = Kalibrera analog styrspak Calibrate D-Pad = Kalibrera D-pad -Calibrated = Calibrated +Calibrated = Kalibrerad Calibration = Kalibrering Circular stick input = Circular stick input Classic = Klassisk @@ -49,13 +49,13 @@ Customize tilt = Anpassa tilt... D-PAD = D-Pad Deadzone radius = Deadzone-radie Disable D-Pad diagonals (4-way touch) = Slå av D-Pad-diagonaler (4-vägs touch) -Disable diagonal input = Disable diagonal input +Disable diagonal input = Blockera diagonal input Double tap = Double tap -Enable gesture control = Enable gesture control +Enable gesture control = Get-kontroll Enable standard shortcut keys = Enable standard shortcut keys Gesture = Gesture -Gesture mapping = Gesture mapping -Glowing borders = Glowing borders +Gesture mapping = Gest-mappning +Glowing borders = Lysande kanter HapticFeedback = Haptic feedback (vibration) Hide touch analog stick background circle = Hide touch analog stick background circle Icon = Icon @@ -83,7 +83,7 @@ Portrait Reversed = Porträtt omvänt PSP Action Buttons = PSP action-knappar Raw input = Raw input Repeat mode = Repeat mode -Reset to defaults = Reset to defaults +Reset to defaults = Återställ till standardvärden Screen aligned to ground = Screen aligned to ground Screen at right angle to ground = Screen at right angle to ground Screen Rotation = Skärmrotation @@ -93,8 +93,8 @@ Sensitivity = Känslighet Shape = Shape Show Touch Pause Menu Button = Show Touch Pause Menu Button Swipe = Swipe -Swipe sensitivity = Swipe sensitivity -Swipe smoothing = Swipe smoothing +Swipe sensitivity = Swipe-känslighet +Swipe smoothing = Swipe-utjämning Thin borders = Tunna kanter Tilt Base Radius = Tilt base radius Tilt Input Type = Lutningstyp @@ -129,7 +129,6 @@ Backend = Backend Bicubic = Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = Buffrad rendering Buy Gold = Buy Gold Control Mapping... = Kontrollmappning... Debugging = Debuggning @@ -138,9 +137,9 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D &11 Disassembly = Disassemblera Discord = Discord -Display Layout Editor = Display layout editor... +Display Layout && Effects = Skärmlayout && effekter... Display Rotation = Skärmrotation -Dump Next Frame to Log = Dump Next Frame to Log +Dump Next Frame to Log = Dumpa nästa frame till loggen Emulation = Emulering Enable Cheats = Fusk Enable Sound = Ljud @@ -148,7 +147,7 @@ Exit = Avsluta Extract File... = Extrahera fil... File = Arkiv Frame Skipping = Frameskipping -Frame Skipping Type = Frame skipping type +Frame Skipping Type = Typ av frame-skippning Fullscreen = Fullskärm Game Settings = Inställningar GE Debugger... = GE Debugger... @@ -173,9 +172,9 @@ Log Console = Loggkonsol Memory View... = Minnesvy... More Settings... = Mer inställningar... Nearest = Nearest -Non-Buffered Rendering = &Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = &Skippa buffereffekter Off = Off -Open Chat = Open Chat +Open Chat = Öppna chat Open Directory... = Öppna mapp... Open from MS:/PSP/GAME... = Öppna från MS:/PSP/GAME... Open Memory Stick = Öppna Memory Stick @@ -185,7 +184,6 @@ Pause = Paus Pause When Not Focused = Pausa vid tappat fokus Portrait = Porträtt Portrait reversed = Porträtt omvänt -Postprocessing Shader = Postprocessing Shader PPSSPP Forums = PPSSPP-forum Record = &Record Record Audio = Record &audio @@ -230,23 +228,21 @@ Create/Open textures.ini file for current game = Create/Open textures.ini file f Current = Aktuellt Dev Tools = Development tools DevMenu = DevMenu -Disabled JIT functionality = Disabled JIT functionality -Draw Frametimes Graph = Draw frametimes graph +Disabled JIT functionality = Avstängd JIT-funktionalitet +Draw Frametimes Graph = Rita upp graf över frame-tider Dump Decrypted Eboot = Dumpa decrypterad EBOOT.BIN när spelet startar -Dump Frame GPU Commands = Dumpa GPU-kommandon för en frame -Enable driver bug workarounds = Enable driver bug workarounds +Dump next frame to log = Dumpa nästa frame till log +Enable driver bug workarounds = Tillåt workarounds för drivrutins-buggar Enable Logging = Debugloggning Enter address = Address FPU = FPU -Framedump tests = Framedump tests +Framedump tests = Framedump-tester Frame Profiler = Frame-profiler -GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU Driver Test = GPU drivrutins-test +GPU log profiler = GPU logg-profiler GPU Profile = GPU profile Jit Compare = Jit-jämförare JIT debug tools = JIT debug tools -Language = Språk -Load language ini = Ladda språk-ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Loggnivå Log View = Log view @@ -256,13 +252,12 @@ No block = Inget block Prev = Föregående Random = Slump Replace textures = Ersätt texturer -Reset = Reset +Reset = Återställ Reset limited logging = Reset limited logging RestoreDefaultSettings = Are you sure you want to restore all settings back to their defaults?\nControl mapping settings are not changed.\n\nYou can't undo this.\nPlease restart PPSSPP for the changes to take effect. RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? Resume = Resume Run CPU Tests = Kör CPU-tester -Save language ini = Spara språk-ini Save new textures = Spara nya texturer Shader Viewer = Shader-visare Show Developer Menu = Visa Developer-menyn @@ -273,15 +268,15 @@ Texture ini file created = Texture ini file created Texture Replacement = Ersätt texturer Toggle Audio Debug = Toggla audio debug Toggle Freeze = Toggla freeze -Touchscreen Test = Touchscreen test +Touchscreen Test = Touchskärm-test VFPU = VFPU [Dialog] * PSP res = * PSP res -Active = Active +Active = Aktiv Back = Tillbaka Cancel = Avbryt -Center = Center +Center = Centrera ChangingGPUBackends = PPSSPP måste starta om för att byta GPU-backend. Vill du starta om nu? ChangingInflightFrames = Changing graphics command buffering requires PPSSPP to restart. Restart now? Channel: = Channel: @@ -289,12 +284,12 @@ Choose PPSSPP save folder = Välj folder att spara i Confirm Overwrite = Vill du skriva över datan? Confirm Save = Vill du spara denna data? ConfirmLoad = Ladda denna data? -ConnectingAP = Connecting to the access point.\nPlease wait... -ConnectingPleaseWait = Connecting.\nPlease wait... -ConnectionName = Connection name -Corrupted Data = Corrupted data -Delete = Ta bort -Delete all = Ta bort allt +ConnectingAP = Kopplar upp till acceesspunkten.\nVänta... +ConnectingPleaseWait = Kopplar upp.\nVänta... +ConnectionName = Uppkopplingsnamn +Corrupted Data = Korrupt data +Delete = Radera +Delete all = Radera allt Delete completed = Borttaget. DeleteConfirm = All sparad data tas bort.\nÄr du säker på att du vill göra detta? DeleteConfirmAll = Vill du verkligen ta bort all\nsparad data för spelet? @@ -311,20 +306,23 @@ Filter = Filter Finish = Färdig GE Frame Dumps = GE Frame Dumps Grid = Grid -Inactive = Inactive -InternalError = An internal error has occurred. +Inactive = Inaktiv +InternalError = Ett internt fel har upptäckts. Load = Ladda Load completed = Laddat. Loading = Laddar\nVänta... LoadingFailed = Kunde inte ladda data. Move = Flytta +Move Down = Flytta ner +Move Up = Flytta upp Network Connection = Nätverksuppkoppling NEW DATA = NY DATA No = Nej ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK -Old savedata detected = Old savedata detected -Options = Options +Old savedata detected = Gammal savedata upptäckt +Options = Inställningar +Remove = Ta bort Reset = Återställ Resize = Ändra storlek Retry = Försök igen @@ -332,7 +330,7 @@ Save = Spara Save completed = Sparat. Saving = Sparar\nVänta... SavingFailed = Kunde inte spara data. -Search = Search +Search = Sök Select = Välj Shift = Skift Skip = Skip @@ -340,20 +338,20 @@ Snap = Snap Space = Mellanslag SSID = SSID Submit = Skicka -Supported = Supported +Supported = Stödd There is no data = Det finns ingen data. Toggle All = Vänd alla Toggle List = Toggle list -Unsupported = Unsupported +Unsupported = Stöds ej When you save, it will load on a PSP, but not an older PPSSPP = When you save, it will load on a PSP, but not an older PPSSPP When you save, it will not work on outdated PSP Firmware anymore = When you save, it will not work on outdated PSP firmware anymore Yes = Ja -Zoom = Zoom +Zoom = Zooma [Error] 7z file detected (Require 7-Zip) = file is compressed (7z).\nPlease decompress first (try 7-Zip or WinRAR). -A PSP game couldn't be found on the disc. = A PSP game couldn't be found on the disc. -Cannot boot ELF located outside mountRoot. = Cannot boot ELF located outside mountRoot. +A PSP game couldn't be found on the disc. = Kunde inte hitta ett PSP-spel på skivavbildningen. +Cannot boot ELF located outside mountRoot. = Kan inte boota en ELF som ligger utanför mountRoot. Could not save screenshot file = Misslyckades spara skärmdump. D3D9or11 = Direct3D 9? (or "no" for Direct3D 11) D3D11CompilerMissing = D3DCompiler_47.dll saknas. Installera, eller tryck Ja för att försöka igen med Direct3D 9 istället. @@ -376,7 +374,7 @@ GenericOpenGLError = Failed initializing graphics. Try upgrading your graphics d GenericVulkanError = Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to OpenGL?\n\nError message: InsufficientOpenGLDriver = Otillräckligt OpenGL-stöd detekterat!\n\nYour GPU reports that it does not support OpenGL 2.0. Would you like to try using DirectX instead?\n\nDirectX is currently compatible with less games, but on your GPU it may be the only choice.\n\nVisit the forums at https://forums.ppsspp.org for more information.\n\n Just a directory. = Endast en katalog. -Missing key = Missing key +Missing key = Nyckel saknas MsgErrorCode = Error code: MsgErrorSavedataDataBroken = Save data was corrupt. MsgErrorSavedataMSFull = Memory Stick full. Check your storage space. @@ -409,7 +407,7 @@ ZIP file detected (Require WINRAR) = file is compressed (ZIP).\nPlease decompres [Game] Asia = Asia -Calculate CRC = Calculate CRC +Calculate CRC = Räkna ut CRC ConfirmDelete = Ta bort Create Game Config = Skapa spelconfig Create Shortcut = Skapa genväg @@ -460,6 +458,8 @@ Aggressive = Aggressiv Alternative Speed = Alternativ hastighet Alternative Speed 2 = Alternativ hastighet 2 (%, 0 = obegränsad) Anisotropic Filtering = Anisotropisk filtrering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Sidförhållande Auto = Auto Auto (1:1) = Auto (1:1) Auto (same as Rendering) = Auto (samma som rendering) @@ -469,11 +469,8 @@ Auto Scaling = Auto scaling Backend = Backend Balanced = Balancerad Bicubic = Bicubisk -BlockTransfer Tip = Vissa spel kräver att denna inställning är på. -BlockTransferRequired = Varning: Detta spel kräver att "Simulera blocktransfer-effekter" är påslaget. Both = Båda Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffrad rendering BufferedRenderingRequired = Warning: This game requires "rendering mode" to be set to "buffered". Camera = Kamera Camera Device = Kamera-enhet @@ -491,16 +488,16 @@ Device = Enhet Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Avstängd -Display layout editor = Skärmlayouteditor +Display Layout && Effects = Skärmlayout och effekter Display Resolution (HW scaler) = Skärmupplösning (HW scaler) -Dump next frame to log = Dumpa nästa frame till log Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Framerate-kontroll -Frame Skipping = Frameskipping +Frame Skipping = Frame-skipping Frame Skipping Type = Frame skipping type FullScreen = Fullskärm -GPU log profiler = GPU log profiler +Geometry shader culling = Geoshader-klippning +GPUReadbackRequired = Varning: Detta spel kräver att 'Skippa dataläsningar från GPU:n' är avstängt. Hack Settings = Hack-inställningar (kan orsaka problem) Hardware Tessellation = Hårdvarutessellering Hardware Transform = Hårdvarutransform @@ -524,8 +521,8 @@ Mode = Mode Must Restart = Starta om PPSSPP för att ändringen ska få effekt. Native device resolution = Native device resolution Nearest = Närmast -No buffer = No buffer -Non-Buffered Rendering = Skippa buffereffekter (snabbare, risk för fel) +No buffer = Ingen buffer +Skip Buffer Effects = Skippa buffereffekter (snabbare, risk för fel) None = Inget Number of Frames = Antal frames Off = Off @@ -534,28 +531,27 @@ Overlay Information = Overlay-information Partial Stretch = Partial stretch Percent of FPS = Procent av FPS Performance = Prestanda -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing-Shader +Postprocessing shaders = Postprocessing-Shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Renderingsläge Rendering Resolution = Renderingsupplösning -RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games -Retain changed textures = Behåll ändrade texturer i cachen (ibland långsammare) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster +RenderingMode NonBuffered Tip = Snabbare, men grafik kan gå sönder Rotation = Rotation Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Skärmskalningsfilter Show Debug Statistics = Visa debugstatistik Show FPS Counter = Visa FPS-räknare -Simulate Block Transfer = Simulera blocktransfer-effekter -Software Rendering = Mjukvarurendering (experiment) +Skip GPU Readbacks = Skippa dataläsningar från GPU:n +Software Rendering = Mjukvarurendering (långsam men ofta mer korrekt) Software Skinning = Software Skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hastighet -Stretching = Stretching +Speed Hacks = Speed-hacks (kan orsaka renderingsproblem) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo-rendering +Stretch = Sträck ut Texture Filter = Texturfilter Texture Filtering = Texturfiltrering Texture Scaling = Texturskalning @@ -628,7 +624,7 @@ Audio = Ljud Controls = Kontroll Graphics = Grafik Networking = Nätverk -Search = Search +Search = Sök System = System Tools = Verktyg @@ -800,39 +796,42 @@ Undo last save = Ångra senaste spar [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4×HqGLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AAColor -Amount = Amount +Amount = Mängd Animation speed (0 -> disable) = Animation speed (0 -> disable) -Black border = Black border -Bloom = Bloom +Black border = Svart kant +Bloom = Bloom-effekt Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Gamma = Gamma -Grayscale = Gråskala -Intensity = Intensity -InverseColors = InverseColors +GreenLevel = Grön-nivå +Intensity = Intensitet +LCDPersistence = LCD-persistens MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural NaturalA = Natural Colors (no blur) Off = Off -Power = Power +Power = Styrka PSPColor = PSP color +RedBlue = Röd/Blå glasögon Saturation = Saturation -Scanlines = Scanlines -Sharpen = Sharpen +Scanlines = Scan-linjer +Sharpen = Skärpa +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleSpline36 = UpscaleSpline36 VideoSmoothingAA = VideoSmoothingAA -Vignette = Vignette +Vignette = Vignett [PSPCredits] all the forum mods = all the forum mods @@ -996,15 +995,15 @@ LoadStateWrongVersion = Misslyckades ladda state: Savestate is for an older vers norewind = No rewind save states available. Playing = Playing PressESC = Tryck ESC för att öppna pausemenyn. -replaceTextures_false = Textures no longer are being replaced. -replaceTextures_true = Texture replacement is enabled. +replaceTextures_false = Texturer ersätts inte längre. +replaceTextures_true = Textur-ersättning är igång. Save State Failed = Misslyckades spara state! Saved State = State sparat saveNewTextures_false = Texture saving was disabled. saveNewTextures_true = Textures will now be saved to your storage. -SpeedCustom2 = Speed: alternate 2 +SpeedCustom2 = Speed: alternativ 2 standard = Hastighet: standard -State load undone = State load undone +State load undone = State load ogjort Untitled PSP game = Untitled PSP game [Search] @@ -1027,6 +1026,8 @@ Uninstall = Avinstallera [SysInfo] %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d hz +%0.2f Hz = %0.2f Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1098,7 +1100,8 @@ Color Saturation = Färgmättnad Color Tint = Färgförskjutning Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. -Floating symbols = Floating symbols +Floating symbols = Flytande symboler +Game crashed = Game crashed Memory Stick folder = Memory Stick-mapp Memory Stick size = Memory Stick-storlek Change Nickname = Ändra nickname @@ -1112,7 +1115,7 @@ Confirmation Button = Bekräftelseknapp Date Format = Datumformat Day Light Saving = Sommartid DDMMYYYY = DDMMYYYY -Decrease size = Decrease size +Decrease size = Minska storlek Developer Tools = Utvecklarverktyg Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid @@ -1128,33 +1131,34 @@ Fast (lag on slow storage) = Snabbt (lag on slow storage) Fast Memory = Snabbt minne (instabilt) Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) frames, 0:off = frames, 0 = avstängt -Games list settings = Games list settings +Games list settings = Inställningar för spel-listan General = Blandat -Grid icon size = Grid icon size +Grid icon size = Ikonstorlek i rutnät Help the PPSSPP team = Stöd PPSSPP-teamet Host (bugs, less lag) = Host (bugs, mindre lagg) Ignore bad memory accesses = Ignorera felaktiga minnesåtkomster -Increase size = Increase size +Increase size = Öka storlek Interpreter = Interpreter IO timing method = IO-timingsmetod IR Interpreter = IR interpreter -Memory Stick Folder = Memory Stick folder -Memory Stick inserted = Memory Stick insatt +Language = Språk +Memory Stick Folder = Memory Stick-mapp +Memory Stick inserted = Memory Stick isatt MHz, 0:default = MHz, 0 = standard MMDDYYYY = MMDDYYYY -Moving background = Moving background -Newest Save = Newest save -No animation = No animation +Moving background = Rörlig bakgrund +Newest Save = Nyaste sparfilen +No animation = Ingen animation Not a PSP game = Inte ett PSP-spel Off = Off -Oldest Save = Oldest save +Oldest Save = Äldsta sparfilen Path does not exist! = Path does not exist! PSP Memory Stick = PSP Memory Stick PSP Model = PSP-modell PSP Settings = PSP-inställningar PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = Recent games +Recent games = Tidigare spel Record Audio = Spela in audio till fil Record Display = Spela in video till fil Reset Recording on Save/Load State = Reset recording on Save/Load state @@ -1167,8 +1171,8 @@ Savestate slot backups = Savestate slot backups Screenshots as PNG = Skärmdumpar som PNG Set UI background... = Välj UI-bakgrund... Show ID = Show ID -Show Memory Stick folder = Show Memory Stick folder -Show region flag = Show region flag +Show Memory Stick folder = Visa Memory Stick-mappen +Show region flag = Visa region-flaggor Simulate UMD delays = Simulera UMD-fördröjningar Slot 1 = Slot 1 Slot 2 = Slot 2 @@ -1177,10 +1181,10 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Lagringsutrymme fullt Sustained performance mode = Sustained performance mode -Theme = Theme +Theme = Tema Time Format = Tidsformat UI = Användargränssnitt -UI background animation = UI background animation +UI background animation = Bakgrundsanimering UI Sound = Ljud i användargränssnittet undo %c = backup %c USB = USB @@ -1192,7 +1196,7 @@ Use X to confirm = Använd X för att bekräfta VersionCheck = Kolla efter nya versioner av PPSSPP WARNING: Android battery save mode is on = WARNING: Android battery save mode is On WARNING: Battery save mode is on = WARNING: Battery save mode is on -Waves = Waves +Waves = Vågor YYYYMMDD = YYYYMMDD [TextureShaders] @@ -1220,3 +1224,17 @@ Details = Detaljer Dismiss = Stäng Download = Ladda ner New version of PPSSPP available = Ny version av PPSSPP tillgänglig + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 5afd25561b..d9661191a8 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -129,7 +129,6 @@ Backend = Rendering &Backend (Restarts PPSSPP) Bicubic = Bicubic Break = Break Break on Load = Break on load -Buffered Rendering = Buffered Rendering Buy Gold = Bilhin ang Gold Control Mapping... = Control Mapping... Debugging = Debug @@ -138,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D 11 Disassembly = Disassembly... Discord = Discord -Display Layout Editor = Display Layout Editor... +Display Layout && Effects = Display Layout & Effects... Display Rotation = Display rotation Dump Next Frame to Log = Dump Next Frame to Log Emulation = Emulasyon @@ -173,7 +172,7 @@ Log Console = Log Console Memory View... = Memory View... More Settings... = Karagdagang settings... Nearest = Nearest -Non-Buffered Rendering = Skip buffer effects (non-buffered, faster) +Skip Buffer Effects = Skip buffer effects Off = Off Open Chat = Open Chat Open Directory... = Buksan ang Directory... @@ -185,7 +184,6 @@ Pause = Pause Pause When Not Focused = Ihinto kapag hindi naka pokus Portrait = Patayo Portrait reversed = Pabaliktad na patayo -Postprocessing Shader = Postprocessing Shader PPSSPP Forums = PPSSPP Forums Record = Record Record Audio = Record audio @@ -233,7 +231,7 @@ DevMenu = DevMenu Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot -Dump Frame GPU Commands = Dump frame GPU commands +Dump next frame to log = I-refresh ang set-up Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Paganahin ang Debug Logging Enter address = Ilagay ang address @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = Ipagkumpara ang JIT JIT debug tools = JIT debug tools -Language = Wika -Load language ini = i-Load ang Language ini Log Dropped Frame Statistics = Log dropped frame statistics Log Level = Level ng Log Log View = Log view @@ -262,7 +258,6 @@ RestoreDefaultSettings = Sigurado ka bang ibalik ang Ssetting sa dati?\nAng Cont RestoreGameDefaultSettings = Sigurado ka bang ibalik sa dati\nang Setting ng isang spesipikong laro?\n\n\nHindi mo na ito maibabalik.\nPaki-restart ang PPSSPP para makita ang mga binago. Resume = Resume Run CPU Tests = Magsagawa ng CPU Tests -Save language ini = Save Language ini Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Ipakita ang Developer Menu @@ -318,6 +313,8 @@ Load completed = Kumpletong na-i load. Loading = Sandali lamang... LoadingFailed = Loading ng datos ay pumalya. Move = Galawin +Move Down = Move Down +Move Up = Move Up Network Connection = Network Connection NEW DATA = BAGONG DATOS No = Hindi @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = Sige Old savedata detected = Nahanap ang lumang savedata Options = Options +Remove = Remove Reset = Ibalik Resize = Resize Retry = Ulitin @@ -460,6 +458,8 @@ Aggressive = Agresibo Alternative Speed = Alternatibong bilis Alternative Speed 2 = Alternatibong bilis 2 (in %, 0 = unlimited) Anisotropic Filtering = Anisotropikong Pagsala +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Awto Auto (1:1) = Awto (1:1) Auto (same as Rendering) = Awto (Kapareho sa Renderig Resolution) @@ -469,11 +469,8 @@ Auto Scaling = Awto scaling Backend = Backend Balanced = Balanse Bicubic = Bicubic -BlockTransfer Tip = Some games require this to be On for correct graphics -BlockTransferRequired = BABALA: This game requires "simulate block transfer effects" to be set to On. Both = Pareho Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Buffered Rendering BufferedRenderingRequired = BABALA: This game requires "rendering mode" to be set to "buffered". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display layout editor = Display layout editor +Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) -Dump next frame to log = I-refresh ang set-up Enable Cardboard VR = Enable Cardboard VR FPS = FPS Frame Rate Control = Pag kontrol ng frame rate Frame Skipping = Frame Skipping Frame Skipping Type = Frame skipping type FullScreen = Isakto sa Sukat ng iyong Iskrin -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack Settings (maaring magdulot ng pagloloko sa laro) Hardware Tessellation = Hardware tessellation Hardware Transform = Hardware Transform @@ -525,7 +522,7 @@ Must Restart = Kailangan i-restart ang PPSSPP upang maging epiktibo ito Native device resolution = Native device resolution Nearest = Pinakamalapit No buffer = No buffer -Non-Buffered Rendering = Skip buffer effects (non-buffered, mabilis) +Skip Buffer Effects = Skip buffer effects (non-buffered, mabilis) None = Wala Number of Frames = Bilang ng frames Off = Patayin @@ -534,28 +531,27 @@ Overlay Information = Overlay na impormasyon Partial Stretch = Parsiyal na unatin Percent of FPS = Porsiyento ng FPS Performance = Performance -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Postprocessing shader +Postprocessing shaders = Postprocessing shaders Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Uri ng Rendering Rendering Resolution = Resolusyon ng rendering RenderingMode NonBuffered Tip = Mabilis, pero minsan wala kang makikita sa laro, blanko -Retain changed textures = Retain changed textures (sometimes slower) -RetainChangedTextures Tip = Makes many games slower, but some games a lot faster Rotation = Rotasyon Safe = Safe -Screen layout = Screen layout Screen Scaling Filter = Screen Scaling Filter Show Debug Statistics = Ipakita ang debug statistics Show FPS Counter = Ipakita ang FPS -Simulate Block Transfer = Simulate block transfer effects +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Software Rendering (Expiremental) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Bilis -Stretching = Iunat +Speed Hacks = Speed Hacks (maaring magdulot ng pagloloko sa laro) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Iunat Texture Filter = Panala ng Texture Texture Filtering = Pagsala sa Texture Texture Scaling = Pagsukat sa Texture @@ -829,8 +825,8 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) 4xHqGLSL = 4テ幽Q GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT scanlines FXAA = FXAA Antialiasing Gamma = Gamma -Grayscale = Grayscale +GreenLevel = Green level Intensity = Intensity -InverseColors = Inverse Colors +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = Off Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Scanlines (CRT) Sharpen = Sharpen +SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Size Uninstall = Uninstall [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (none detected) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Name D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Device info Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Lumulutang na simbolo +Game crashed = Game crashed +Language = Wika Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Baguhin ang palayaw @@ -1220,3 +1224,17 @@ Details = Detalye Dismiss = Dismiss Download = Download New version of PPSSPP available = Meron nang bagong bersiyon ang PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index c63fa3125b..5c4544d9df 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -129,7 +129,6 @@ Backend = การแสดงผลที่สนับสนุน (ต้ Bicubic = ไบคิวบิค Break = หยุด Break on Load = หยุดเมื่อโหลด -Buffered Rendering = การแสดงผลแบบใช้บัฟเฟอร์ Buy Gold = ซื้อแบบตัวสีทอง Control Mapping... = แผงปรับการคุมควบ... Debugging = แก้ไขจุดบกพร่อง @@ -138,7 +137,7 @@ Direct3D9 = ไดเร็คท์ 3D 9 Direct3D11 = ไดเร็คท์ 3D 11 Disassembly = การแยกองค์ประกอบ... Discord = ไปที่ Discord -Display Layout Editor = แก้ไขรูปแบบของหน้าจอ... +Display Layout && Effects = รูปแบบหน้าจอ และเอฟเฟ็คท์ Display Rotation = การสลับหมุนหน้าจอ Dump Next Frame to Log = ดึงข้อมูลของเฟรมถัดไปเพื่อเก็บบันทึกค่า Emulation = การจำลอง @@ -173,7 +172,7 @@ Log Console = เก็บค่าคอนโซล Memory View... = มุมมองค่าความจำ... More Settings... = การตั้งค่าอื่นๆ... Nearest = แบบใกล้เคียง -Non-Buffered Rendering = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) +Skip Buffer Effects = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) Off = ปิด Open Chat = เปิดหน้าต่างแชท Open Directory... = เปิดแหล่งที่เก็บ... @@ -185,7 +184,6 @@ Pause = หยุดชั่วคราว Pause When Not Focused = หยุดชั่วคราวเมื่อไม่ได้เล่น Portrait = แนวตั้ง Portrait reversed = แนวตั้งกลับด้าน -Postprocessing Shader = กระบวนการทำงานไล่ปรับเฉดแสงสี PPSSPP Forums = เว็บ PPSSPP Forums Record = การอัดบันทึก Record Audio = อัดบันทึกเสียง @@ -200,7 +198,7 @@ Save Map File... = บันทึกไฟล์ Map... Save State = เซฟสเตทเกม Save State File... = ไฟล์เซฟสเตทเกม... Savestate Slot = ช่องเซฟสเตทเกม -Screen Scaling Filter = ตัวกรองขนาดของหน้าจอ +Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ Show Debug Statistics = แสดงค่าทางสถิติการแก้ไขจุดบกพร่อง Show FPS Counter = แสดงตัวจับค่าเฟรมเรท/วินาที Skip Number of Frames = อิงจากค่าจำนวนเฟรม @@ -233,7 +231,7 @@ DevMenu = เมนูผู้พัฒนา Disabled JIT functionality = ปิดฟังก์ชั่นการทำงานของระบบ JIT Draw Frametimes Graph = กราฟแสดงจำนวนเฟรม Dump Decrypted Eboot = ดึงไฟล์ EBOOT.BIN ออกมาเก็บไว้เมื่อเริ่มเกม -Dump Frame GPU Commands = ดึงค่าเฟรมคำสั่งของ GPU +Dump next frame to log = ดึงข้อมูลของเฟรมถัดไปเก็บบันทึกค่า Enable Logging = เปิดใช้งานการเก็บค่าแก้ไขจุดบกพร่อง Enable driver bug workarounds = เปิดใช้งานการแก้ขัดปัญหาไดรเวอร์บั๊ก Enter address = ใส่ค่าที่อยู่ @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = ทดสอบไฟล์เฟรมดั๊มพ์ Frame Profiler = รายละเอียดของเฟรม GPU Driver Test = ทดสอบไดรเวอร์ GPU -GPU Log Profiler = ตัวแสดงค่าโปรไฟล์ GPU +GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU GPU Profile = โปรไฟล์ GPU Jit Compare = เปรียบเทียบระบบ JIT JIT debug tools = เครื่องมือตรวจสอบระบบ JIT -Language = ภาษา -Load language ini = โหลดไฟล์ภาษา (.ini) Log Dropped Frame Statistics = เก็บสถิติค่าเฟรมเรทตก Log Level = เก็บค่าระดับ Log View = เก็บค่ามุมมอง @@ -262,14 +258,13 @@ RestoreDefaultSettings = คุณแน่ใจรึว่าต้องก RestoreGameDefaultSettings = คุณแน่ใจรึว่าต้องการรีเซ็ตตั้งค่าเฉพาะเกม?\nการตั้งค่าของเกมนี้จะกลับไปใช้ค่าเริ่มต้นของ PPSSPP? Resume = เล่นต่อ Run CPU Tests = เรียกใช้การทดสอบซีพียู -Save language ini = บันทึกไฟล์ภาษา (.ini) Save new textures = บันทึกพื้นผิวลงในแหล่งที่เก็บข้อมูล -Shader Viewer = มุมมองการปรับไล่เฉดแสงสี +Shader Viewer = มุมมองการปรับเฉดแสงสี Show Developer Menu = แสดงเมนูสำหรับนักพัฒนา Show on-screen messages = แสดงข้อความการแจ้งเตือนต่างๆ Stats = สถิติ System Information = ข้อมูลโดยรวมของระบบ -Texture ini file created = Texture ini file created +Texture ini file created = ไฟล์ Texture.ini ได้ถูกสร้างแล้ว Texture Replacement = การแทนที่พื้นผิว Toggle Audio Debug = แก้ไขจุดบกพร่องของเสียง Toggle Freeze = ปุ่มแช่แข็ง @@ -318,6 +313,8 @@ Load completed = โหลดข้อมูลสำเร็จ Loading = กำลังโหลด\nโปรดรอ... LoadingFailed = ไม่สามารถโหลดข้อมูลนี้ได้ Move = ย้าย +Move Down = ย้ายลงล่าง +Move Up = ย้ายขึ้นบน Network Connection = การเชื่อมต่อเครือข่าย NEW DATA = ข้อมูลใหม่ No = ไม่ใช่ @@ -325,7 +322,8 @@ ObtainingIP = กำลังรับไอพี\nโปรดรอสัก OK = ตกลง Old savedata detected = ตรวจพบข้อมูลเซฟเก่า Options = ตัวเลือก -Reset = ตั้งค่าใหม่ +Remove = ลบออก +Reset = รีเซ็ต Resize = ขนาด Retry = ลองใหม่ Save = บันทึก @@ -460,6 +458,8 @@ Aggressive = รุนแรง Alternative Speed = เพิ่ม-ลดระดับความเร็ว (ใน %, 0 = ไม่จำกัด) Alternative Speed 2 = เพิ่ม-ลดระดับความเร็ว 2 (ใน %, 0 = ไม่จำกัด) Anisotropic Filtering = ตัวกรองขจัดความไม่คมชัดของพื้นผิว +Antialiasing (MSAA) = ลดรอยหยักภาพ (แบบ MSAA) +Aspect Ratio = สัดส่วนหน้าจอ Auto = อัตโนมัติ Auto (1:1) = อัตโนมัติ (1:1) Auto (same as Rendering) = อัตโนมัติ (ค่าเดียวกับที่ใช้แสดงผลภาพ) @@ -469,11 +469,8 @@ Auto Scaling = สเกลอัตโนมัติ Backend = การสนับสนุนกราฟิก Balanced = สมดุล Bicubic = ไบคิวบิค -BlockTransfer Tip = บางเกมจำเป็นต้องเปิดใช้งานเพื่อการแสดงผลที่ถูกต้อง -BlockTransferRequired = คำเตือน: เกมนี้ต้องปรับใช้งาน "จำลองผลปิดกั้นการส่งผ่านข้อมูลเอฟเฟ็คท์" ด้วย Both = ใช้ทั้งคู่ Buffer graphics commands (faster, input lag) = ควบคุมกราฟิกบัฟเฟอร์ (เร็วขึ้น, อาจทำให้เกิดอินพุตแล็ก) -Buffered Rendering = การแสดงผลแบบใช้บัฟเฟอร์ BufferedRenderingRequired = คำเตือน: เกมนี้ต้องปรับใช้งานในโหมด "การแสดงผลแบบใช้บัฟเฟอร์" Camera = กล้อง Camera Device = กล้องที่พร้อมใช้งาน @@ -491,21 +488,21 @@ Device = การ์ดจอ Direct3D 9 = ไดเร็คท์ 3D 9 Direct3D 11 = ไดเร็คท์ 3D 11 Disabled = ปิดการใช้งาน -Display layout editor = แก้ไขรูปแบบของหน้าจอ +Display Layout && Effects = รูปแบบหน้าจอ และเอฟเฟ็คท์ Display Resolution (HW scaler) = ความละเอียดหน้าจอ (ตามฮาร์ดแวร์) -Dump next frame to log = ดึงข้อมูลของเฟรมถัดไปเก็บบันทึกค่า Enable Cardboard VR = เปิดการทำงานแว่นการ์ดบอร์ด VR FPS = เฟรมต่อวิ Frame Rate Control = การควบคุมเฟรมเรท Frame Skipping = ข้ามเฟรม Frame Skipping Type = รูปแบบการข้ามเฟรม FullScreen = เต็มหน้าจอ -GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU +Geometry shader culling = การคัดแยกเฉดสีเชิงเรขาคณิต +GPUReadbackRequired = คำเตือน: เกมนี้จำเป็นต้องติ๊กตั้งค่า "ข้ามการอ่านข้อมูลส่งกลับไปยัง GPU" ออกด้วย Hack Settings = ตั้งค่าการปรับแฮ็ค (อาจแสดงผลผิดพลาด) Hardware Tessellation = ฮาร์ดแวร์ เทสเซลเลชั่น Hardware Transform = ใช้ฮาร์ดแวร์ในการแปลงค่าประมวลผล hardware transform error - falling back to software = การแปลงค่าจากฮาร์ดแวร์ล้มเหลว กลับไปใช้การแปลงค่าจากซอฟต์แวร์ -HardwareTessellation Tip = ใช้ฮาร์ดแวร์ในการสร้างเส้นโค้ง Spline/Bezier ช่วยปรับปรุงคุณภาพเส้นให้คงที่ +HardwareTessellation Tip = ใช้ฮาร์ดแวร์ในการสร้างเส้นโค้ง High = สูง Hybrid = ไฮบริด Hybrid + Bicubic = ไฮบริด + ไบคิวบิค @@ -516,8 +513,8 @@ Lazy texture caching Tip = เร็วขึ้น แต่อาจจะท Linear = แบบเชิงเส้น Low = ต่ำ LowCurves = ระดับของเส้นโค้ง Spline/Bezier -LowCurves Tip = ปรับเพิ่ม-ลดคุณภาพในการแสดงผลของเส้นโค้ง Spline/Bezier -Lower resolution for effects (reduces artifacts) = ลดความละเอียดของเอฟเฟ็คต์ให้ต่ำลง (แก้ภาพสว่างจ้า) +LowCurves Tip = ใช้แค่ในบางเกม ช่วยปรับคุณภาพของเส้นโค้งให้มีความเรียบเนียนขึ้น +Lower resolution for effects (reduces artifacts) = ลดความละเอียดของเอฟเฟ็คต์ให้ต่ำลง (ลดขอบภาพสว่าง) Manual Scaling = กำหนดขนาดเอง Medium = ปานกลาง Mode = โหมด @@ -525,7 +522,7 @@ Must Restart = คุณควรรีสตาร์ท PPSSPP อีกคร Native device resolution = ค่าความละเอียดดั้งเดิมของอุปกรณ์ Nearest = แบบใกล้เคียง No buffer = ไม่ใช้บัฟเฟอร์ -Non-Buffered Rendering = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) +Skip Buffer Effects = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) None = ไม่มี Number of Frames = อิงจากค่าจำนวนเฟรม Off = ปิด @@ -534,33 +531,32 @@ Overlay Information = การแสดงข้อมูลซ้อนทั Partial Stretch = แนวตั้งดึงเต็มจอ Percent of FPS = อิงจากเปอร์เซ็นต์เฟรมต่อวิ Performance = ประสิทธิภาพ -Postprocessing effect = กระบวนการทำงานไล่ปรับเอฟเฟ็คท์ -Postprocessing Shader = กระบวนการทำงานไล่ปรับเฉดแสงสี +Postprocessing shaders = กระบวนการทำงานปรับเฉดแสงสี Recreate Activity = สร้างกิจกรรมใหม่ Render duplicate frames to 60hz = แสดงผลเฟรมซ้ำให้ถึง 60 เฮิร์ตซ RenderDuplicateFrames Tip = ช่วยให้ภาพดูลื่นตาขึ้น ในเกมที่ใช้เฟรมเรทต่ำ Rendering Mode = โหมดที่ใช้ในการแสดงผล Rendering Resolution = ความละเอียดในการแสดงผลภาพ -RenderingMode NonBuffered Tip = เร็วขึ้นก็จริง แต่มีผลข้างเคียงในบางเกมอาจเกิดอาการจอดำ -Retain changed textures = รักษาความเปลี่ยนแปลงของพื้นผิว (ช้าลงในบางครั้ง) -RetainChangedTextures Tip = มีหลายเกมที่ปรับใช้แล้วความเร็วตกลง แต่ในบางเกมความเร็วก็เพิ่มขึ้น +RenderingMode NonBuffered Tip = เร็วขึ้นก็จริง แต่กราฟิกอาจจะขาดหายไปในบางเกม Rotation = หมุนจอ Safe = ปลอดภัย -Screen layout = เค้าโครงหน้าจอ Screen Scaling Filter = ตัวกรองปรับสเกลหน้าจอ Show Debug Statistics = แสดงค่าทางสถิติการแก้ไขจุดบกพร่อง Show FPS Counter = แสดงค่าเฟรมเรท และความเร็ว/วินาที -Simulate Block Transfer = จำลองผลปิดกั้นการส่งผ่านข้อมูลเอฟเฟ็คท์ -Software Rendering = ใช้ซอฟต์แวร์ในการแสดงผล (ช้า) +Skip GPU Readbacks = ข้ามการอ่านข้อมูลส่งกลับไปยัง GPU +Software Rendering = ใช้ซอฟต์แวร์ในการแสดงผล (ช้า แต่แม่นยำ) Software Skinning = ซอฟต์แวร์ สกินนิ่ง SoftwareSkinning Tip = ผสานโมเดลพื้นผิวให้เขียนผ่านซีพียู ซึ่งเกมส่วนใหญ่ปรับใช้แล้วไวขึ้น Speed = ความเร็ว -Stretching = ดึงเต็มจอ +Speed Hacks = แฮ็คความเร็ว (อาจแสดงผลผิดพลาด) +Stereo display shader = เฉดแสงสีของภาพแบบสามมิติ +Stereo rendering = การแสดงผลแบบสามมิติ +Stretch = ดึงเต็มจอ Texture Filter = ตัวกรองพื้นผิว Texture Filtering = การกรองพื้นผิว Texture Scaling = การปรับสเกลพื้นผิว Texture Shader = โทนแสงสีพื้นผิว -Turn off Hardware Tessellation - unsupported = ปิด "ฮาร์ดแวร์ เทสเซลเลชั่น" เนื่องจากไม่สนับสนุนการทำงาน +Turn off Hardware Tessellation - unsupported = ปิด "ฮาร์ดแวร์ เทสเซลเลชั่น" แล้ว เนื่องจากไม่สนับสนุนการทำงาน Unlimited = ไม่จำกัด Up to 1 = เพิ่มไปที่ 1 Up to 2 = เพิ่มไปที่ 2 @@ -599,7 +595,7 @@ Show PSP = แสดง PSP You can press ESC to cancel. = คุณสามารถกด ESC เพื่อยกเลิกได้ [MainMenu] -Browse = เรียกใช้... +Browse = เรียกดู... Buy PPSSPP Gold = ซื้อ PPSSPP Gold Choose folder = เลือกโฟลเดอร์ Credits = เครดิต @@ -610,17 +606,17 @@ Give PPSSPP permission to access storage = อนุญาตให้สิท Homebrew & Demos = เกมโฮมบริว&&เกมทดลองเล่น How to get games = ต้องทำอย่างไรถึงจะได้รอมเกมมา? How to get homebrew & demos = วิธีการรับเกมโฮมบริว&&เกมทดลองเล่น? -Load = โหลดเกม... +Load = โหลด... Loading... = กำลังโหลด... PinPath = ปักหมุด PPSSPP can't load games or save right now = --- ไม่สามารถโหลดเข้าเกมหรือข้อมูลเซฟได้ในขณะนี้ --- -PPSSPP Homebrew Store = ดาวน์โหลดจาก PPSSPP โฮมบริวสโตร์ +PPSSPP Homebrew Store = PPSSPP โฮมบริวสโตร์ Recent = เกมที่พึ่งเล่นล่าสุด SavesAreTemporary = PPSSPP จะเซฟข้อมูลในโฟลเดอร์ชั่วคราว SavesAreTemporaryGuidance = แนะนำให้แตกไฟล์ PPSSPP ก่อนที่จะใช้งานนะจ้ะ เซฟจะได้ไม่บิน SavesAreTemporaryIgnore = ไม่สนคำเตือน UnpinPath = ถอนหมุด -UseBrowseOrLoad = ใช้ตัวเลือก เรียกใช้... เพื่อเลือกโฟลเดอร์ หรือ โหลด... เพื่อเลือกไฟล์ +UseBrowseOrLoad = ใช้ตัวเลือก เรียกดู... เพื่อเลือกโฟลเดอร์ หรือ โหลด... เพื่อเลือกไฟล์ www.ppsspp.org = เว็บไซต์หลัก PPSSPP [MainSettings] @@ -640,6 +636,7 @@ An.Left = อนาล็อก(ซ้าย)ซ้าย An.Right = อนาล็อก(ซ้าย)ขวา An.Up = อนาล็อก(ซ้าย)ขึ้น Analog limiter = ตัวจำกัดปุ่มอนาล็อก +Analog speed = ความเร็วอนาล็อก Analog Stick = ปุ่มอนาล็อก Audio/Video Recording = อัดบันทึกวีดีโอ/เสียง AxisSwap = สลับด้านแกน @@ -756,8 +753,8 @@ Center Left = มุมกลางซ้ายจอ Center Right = มุมกลางขวาจอ Change Mac Address = เปลี่ยนค่าที่อยู่ Mac Change proAdhocServer Address = เปลี่ยนไอพีที่อยู่ของเซิร์ฟเวอร์ Pro Adhoc (localhost = แลนในเครื่องเดียวกัน) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = ต้องการสร้างค่า MAC address ใหม่? +ChangeMacSaveWarning = บางเกมจะตรวจสอบค่า MAC address ตอนโหลดข้อมูลเซฟ เพราะงั้นอาจจะทำให้เซฟอันเก่าใช้งานไม่ได้ Chat = แชท Chat Button Position = ปุ่มตำแหน่งแชท Chat Here = แชทที่นี่ @@ -823,40 +820,46 @@ Rewind = โหลดสเตทพื้นหลัง Save State = เซฟสเตทเกม Settings = การตั้งค่า Switch UMD = สลับแผ่น UMD -Undo last load = เลิกทำโหลดครั้งล่าสุด -Undo last save = เลิกทำเซฟครั้งล่าสุด +Undo last load = ย้อนคืนโหลดครั้งล่าสุด +Undo last save = ย้อนคืนเซฟครั้งล่าสุด [PostShaders] (duplicated setting, previous slider will be used) = (การตั้งค่าที่ซ้ำซ้อนกัน อาจจะใช้แถบเลื่อนก่อนหน้า) -4xHqGLSL = ภาพคมชัดคูณ 4 -5xBR = ภาพคมชัดคูณ 5 -5xBR-lv2 = ภาพคมชัดคูณ 5 (เวอร์ชั่น 2) +4xHqGLSL = ภาพอัพสเกลพิกเซลอาร์ตคูณ 4 +5xBR = ภาพอัพสเกลพิกเซลอาร์ตคูณ 5 +5xBR-lv2 = ภาพอัพสเกลพิกเซลอาร์ตคูณ 5 (เวอร์ชั่น 2) AAColor = ภาพดูมีสีสัน Amount = ระดับ Animation speed (0 -> disable) = ความเร็วอนิเมชั่น (0 = ปิดใช้งาน) +Aspect = ทิศทาง Black border = ขอบดำ Bloom = ภาพสว่างขึ้น Brightness = แสงสว่าง Cartoon = ภาพออกแนวการ์ตูน CatmullRom = ภาพอัพสเกลแบบไบคิวบิค (แคทมิว-รอม) ColorCorrection = ภาพสีสมจริง +ColorPreservation = การเก็บรักษาสีเดิม Contrast = ความคมชัด CRT = ภาพออกโทนเหลืองขึ้นเส้น FXAA = ภาพเน้นลบขอบรอยหยัก Gamma = แกมม่า -Grayscale = ภาพโทนสีเทา +GreenLevel = ระดับสีเขียว Intensity = ความเข้มของแสง InverseColors = ภาพสีกลับ +LCDPersistence = ภาพ LCD แบบค้างคา MitchellNetravali = ภาพอัพสเกลแบบไบคิวบิค (มิทเชลล์-เนทราวาลิ) Natural = ภาพเน้นสีธรรมชาติ NaturalA = ภาพเน้นสีธรรมชาติ (ไม่เบลอ) Off = ปิด Power = ความเข้ม PSPColor = ภาพสีแบบเครื่อง PSP +RedBlue = ภาพแว่นแดงฟ้า (สามมิติแบบซ้อนเหลื่อม) Saturation = ความอิ่มตัวของสี Scanlines = ภาพออกมัวเป็นเส้นแนวนอน Sharpen = ภาพเน้นขอบคมขึ้น +SideBySide = ภาพแยกสองจอแบบสามมิติ SSAA(Gauss) = ภาพเน้นความละเอียดให้สูงขึ้น +Strength = ความเด่นชัด Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleSpline36 = ภาพลดความละเอียด เน้นสเกลคมขึ้น @@ -1013,6 +1016,7 @@ Filter = ตัวกรอง Filtering settings by '%1' = ตัวกรองตั้งค่าที่ค้นพบโดย '%1' Find settings = ค้นหาตัวเลือกตั้งค่า No settings matched '%1' = ไม่มีตั้งค่าที่ตรงกันกับ '%1' +Search term = คำที่ต้องการค้นหา [Store] Already Installed = ติดตั้งเรียบร้อยแล้ว @@ -1025,9 +1029,11 @@ Size = ขนาด Uninstall = ถอนการติดตั้ง [SysInfo] +%0.2f Hz = %0.2f เฮิร์ต %d (%d per core, %d cores) = %d (%d เธรด ต่อคอร์, %d คอร์) %d bytes = %d ไบต์ -(none detected) = (ไม่พบ) +%d Hz = %d เฮิร์ต +(none detected) = (ไม่มีการตรวจพบ) 3D API = แอพพลิเคชั่น โปรแกรม อินเตอร์เฟซ สามมิติ ABI = แอพพลิเคชั่น ไบนารี่ อินเตอร์เฟซ API Version = เวอร์ชั่นของแอพพลิเคชั่น โปรแกรม อินเตอร์เฟซ @@ -1044,21 +1050,24 @@ CPU Name = ชื่อหน่วยประมวลผลหลัก D3DCompiler Version = เวอร์ชั่นตัวคอมไพล์ของ D3D Debug = แก้ไขบั๊ก Debugger Present = ตัวช่วยแก้ไขบั๊ก +Depth buffer format = รูปแบบบัฟเฟอร์ความลึก Device Info = ข้อมูลอุปกรณ์ Directories = เส้นทางเก็บข้อมูล Display Color Formats = รูปแบบสีของหน้าจอแสดงผล Display Information = ข้อมูลของหน้าจอแสดงผล -Driver bugs = Driver bugs +Driver bugs = ไดรเวอร์บั๊ก Driver Version = เวอร์ชั่นของไดรเวอร์ EGL Extensions = ส่วนขยายอีจีแอล Frames per buffer = จำนวนเฟรมต่อบัฟเฟอร์ +GPU Flags = แฟล็กของหน่วยประมวลผลกราฟิก GPU Information = ข้อมูลของหน่วยประมวลผลกราฟิก High precision float range = ขอบเขตจำนวนทศนิยมช่วงค่าความแม่นยำสูง High precision int range = ขอบเขตจำนวนเต็มช่วงค่าความแม่นยำสูง +JIT available = JIT ใช้งานได้ Lang/Region = ภาษา/ภูมิภาค Memory Page Size = ขนาดหน้าของหน่วยความจำ Native Resolution = ความละเอียดดั้งเดิม -No GPU driver bugs detected = No GPU driver bugs detected +No GPU driver bugs detected = ไม่พบไดรเวอร์บั๊กใน GPU รุ่นนี้ OGL Extensions = ส่วนขยายโอจีแอล OpenGL ES 2.0 Extensions = ส่วนขยายของโอเพ่นจีแอล อีเอส 2.0 OpenGL ES 3.0 Extensions = ส่วนขยายของโอเพ่นจีแอล อีเอส 3.0 @@ -1083,6 +1092,7 @@ Vendor (detected) = ผู้จัดจำหน่าย (ที่ตรว Version Information = ข้อมูลของเวอร์ชั่น Vulkan Extensions = ส่วนขยายของวัลแคน Vulkan Features = ฟีเจอร์วัลแคน +UI Resolution = ความละเอียดของอินเตอร์เฟซ [System] (broken) = (เสียหาย) @@ -1126,6 +1136,7 @@ Fast Memory = หน่วยความจำทำงานได้เร็ Floating symbols = สัญลักษณ์ปุ่มจอยลอยไปมา Force real clock sync (slower, less lag) = บังคับการซิงค์สัญญาณความถี่ (ช้ากว่า, เเล็กน้อยลง) frames, 0:off = เฟรม, 0 = ปิด +Game crashed = Game crashed Games list settings = การตั้งค่าในรายการเกม General = ทั่วไป Grid icon size = ขนาดของไอคอนเกม @@ -1136,6 +1147,7 @@ Increase size = เพิ่มขนาดไอคอน Interpreter = อินเตอร์พรีเตอร์ IO timing method = ทางเลือกคำนวณเวลา รับ/ส่ง ข้อมูล IR Interpreter = ไออาร์ อินเตอร์พรีเตอร์ +Language = ภาษา Memory Stick folder = เปลี่ยนแหล่งที่เก็บข้อมูล (เม็มโมรี่ สติ๊ก) Memory Stick Folder = โฟลเดอร์แหล่งที่เก็บข้อมูล (เม็มโมรี่ สติ๊ก) Memory Stick inserted = ใส่ที่บันทึกข้อมูล (เม็มโมรี่ สติ๊ก) @@ -1221,3 +1233,17 @@ Details = รายละเอียด Dismiss = ยกเลิก Download = ดาวน์โหลด New version of PPSSPP available = PPSSPP เวอร์ชั่นใหม่พร้อมให้ดาวน์โหลดแล้ว! + +[VR] +% of native FoV = % ของค่า FoV ดั้งเดิม +6DoF movement = การเคลื่อนไหวแบบ 6DoF +Distance to 2D menus and scenes = ระยะห่างจากเมนูสองมิติ และฉาก +Field of view scale = สเกลของมุมมองพื้นที่รอบตัว +Force 72Hz update = บังคับรีเฟรชเรทไปที่ 72Hz +Heads-up display scale = สเกลขนาดของ HUD +Map controller movements to keys = เซ็ตปุ่มควบคุมด้วยท่าทางผ่านจอย +Motion needed to generate action = จำเป็นต้องขยับท่าทางเพื่อเซ็ตปุ่มที่ต้องการ +Stereoscopic vision (Experimental) = มุมมองภาพแบบสามมิติ (ขั้นทดสอบ) +Virtual reality = ความเป็นจริงเสมือน +VR camera = กล้อง VR +VR controllers = จอยควบคุม VR diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index d6c04817fd..d346a92b5e 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1,12 +1,12 @@ [Audio] -Alternate speed volume = Alternatif hız sesi +Alternate speed volume = Alternatif hız hacmi Audio backend = Ses alttabanı (Yeniden başlatma gerekir) Audio Error = Ses Hatası -AudioBufferingForBluetooth = Bluetooth-uyumlu arabellek (daha yavaş) -Auto = Auto +AudioBufferingForBluetooth = Bluetooth uyumlu arabellek (daha yavaş) +Auto = Otomatik Device = Cihaz Disabled = Devre dışı -DSound (compatible) = DSound (Uyumlu) +DSound (compatible) = DSound (uyumlu) Enable Sound = Sesi etkinleştir Global volume = Genel ses Microphone = Mikrofon @@ -15,10 +15,10 @@ Mute = Sessiz Reverb volume = Yankı sesi Use new audio devices automatically = Otomatik olarak yeni ses cihazlarını kullan Use global volume = Genel ses seviyesini kullan -WASAPI (fast) = WASAPI (Hızlı) +WASAPI (fast) = WASAPI (hızlı) [Controls] -Analog Binding = Analog Binding +Analog Binding = Analog Bağlama Analog Limiter = Analog sınırlayıcı Analog Settings = Analog Ayarları Analog Stick = Analog çubuk @@ -31,9 +31,9 @@ Auto-rotation speed = Otomatik rotasyon hızı Auto-switch = Oto-switch Base tilt position = Base tilt position Binds = Binds -Button Binding = Button Binding +Button Binding = Düğme Bağlama Button Opacity = Tuş görünürlüğü -Button style = Tuş biçimi +Button style = Tuş stili Calibrate Analog Stick = Analog Çubuğu Kalibre Et Calibrate D-Pad = D-Pad'i kalibre et Calibrated = Kalibre edildi @@ -44,7 +44,7 @@ Confine Mouse = Fareyi belirli bir pencere/görüntü alanı içinde sınırla Control Mapping = Kontrolleri Ayarla Custom Key Setting = Özel Tuş Ayarı Customize = Düzenle -Customize Touch Controls = Dokunmatik kontrol düzenini düzenle... +Customize Touch Controls = Dokunmatik kontrolleri düzenle... Customize tilt = Eğimi düzenle... D-PAD = D-Pad Deadzone radius = Ölü bölge yarıçapı @@ -70,22 +70,22 @@ L/R Trigger Buttons = L/R Tetik düğmeleri Landscape = Yatay Landscape Auto = Otomatik yatay Landscape Reversed = Ters yatay -Low end radius = Low end radius +Low end radius = Düşük uç yarıçapı Mouse = Fare ayarları Mouse sensitivity = Fare hassasiyeti Mouse smoothing = Fare yumuşatma MouseControl Tip = Fareye 'Kontrolleri Ayarlama' bölümünden 'M' simgesine basarak kontrol atayabilirsiniz. -None (Disabled) = Hiçbiri (Devre Dışı) +None (Disabled) = Hiçbiri (Devre dışı) Off = Kapalı OnScreen = Dokunmatik ekran kontrolleri Portrait = Dikey Portrait Reversed = Ters dikey PSP Action Buttons = PSP eylem tuşları -Raw input = Ham girdi -Repeat mode = Repeat mode +Raw input = Saf girdi +Repeat mode = Tekrar modu Reset to defaults = Varsayılanlara sıfırla Screen aligned to ground = Ekran yere hizalansın -Screen at right angle to ground = Screen at right angle to ground +Screen at right angle to ground = Yere dik açıda ekran Screen Rotation = Ekran rotasyonu seconds, 0 : off = saniyeler, 0 = kapalı Sensitivity (scale) = Hassasiyet (ölçek) @@ -101,7 +101,7 @@ Tilt Input Type = Eğim giriş türü Tilt Sensitivity along X axis = X ekseni boyunca eğim hassasiyeti Tilt Sensitivity along Y axis = Y ekseni boyunca eğim hassasiyeti To Calibrate = Kalibre etmek için cihazı düz bir zemine yerleştirin ve "Kalibre et" tuşuna basın. -Toggle mode = Toggle mode +Toggle mode = Geçiş modu Touch Control Visibility = Dokunmatik kontrol görünürlüğü Use custom right analog = Özel sağ analog kullan Use Mouse Control = Fareyle kontrolü etkinleştir @@ -116,7 +116,7 @@ Edit Cheat File = Hile dosyasını düzenle Enable/Disable All = Bütün hileleri Aç/Kapat Import Cheats = cheat.db'den hile al Options = Ayarlar -Refresh Rate = Yenileme hızı +Refresh Rate = Yenileme Hızı [DesktopUI] # EN: If your language does not show well with the default font, you can use Font to specify a different one. @@ -131,7 +131,6 @@ Backend = Oluşturma &Arkaucu (PPSSPP'yi yeniden başlatır) Bicubic = &Bikübik Break = Break Break on Load = Break on load -Buffered Rendering = &Tampon bellek ile oluştur Buy Gold = Altın Sürümünü Satın Al Control Mapping... = Kontrol Ayarlama... Debugging = &Hata Ayıklama @@ -140,7 +139,7 @@ Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 Disassembly = &Disassembly... Discord = Discord -Display Layout Editor = Ekran düzeni düzenleyici... +Display Layout && Effects = Ekran düzeni düzenleyici... Display Rotation = Ekran rotasyonu Dump Next Frame to Log = D&ump Next Frame to Log Emulation = &Emülasyon @@ -175,7 +174,7 @@ Log Console = &Günlük Konsolu Memory View... = Bellek &Görünümü... More Settings... = &Daha Fazla Ayar... Nearest = &En Yakın -Non-Buffered Rendering = &Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) +Skip Buffer Effects = &Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) Off = &Kapalı Open Chat = Open Chat Open Directory... = Dizin Aç... @@ -187,7 +186,6 @@ Pause = PPSSPP Menüsü Pause When Not Focused = &Başka programa geçildiğinde duraklat Portrait = Dikey Portrait reversed = Ters Dikey -Postprocessing Shader = Postprocessin&g Shader PPSSPP Forums = PPSSPP Forumları Record = Kayıt Record Audio = Ses Kaydet @@ -235,7 +233,7 @@ DevMenu = DevMenu Disabled JIT functionality = JIT işlevselliğini devre dışı bırakın Draw Frametimes Graph = Kare süreleri grafiğini çizin Dump Decrypted Eboot = Şifresi çözülmüş EBOOT.BIN'i oyun açılışında temizleyin -Dump Frame GPU Commands = Kare GPU komutlarını temizleyin +Dump next frame to log = Sonraki kareyi günlüğe dökümle Enable driver bug workarounds = Sürücü hatası geçici çözümlerini etkinleştirin Enable Logging = Hata ayıklama günlüğünü etkinleştirin Enter address = Adres Gir @@ -243,12 +241,10 @@ FPU = FPU Framedump tests = Framedump testleri Frame Profiler = Frame profiler GPU Driver Test = GPU sürücü testi -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profili Jit Compare = Jit karşılaştırma JIT debug tools = JIT hata ayıklama araçları -Language = Dil -Load language ini = Dil Dosyası Yükle(.ini) Log Dropped Frame Statistics = Düşen kare istatistiklerini günlüğe kaydet Log Level = Günlük seviyesi Log View = Günlük görünümü @@ -264,7 +260,6 @@ RestoreDefaultSettings = Bütün ayarları varsayılanlarına döndürmek istedi RestoreGameDefaultSettings = Oyun için ayarlanmış olan özel ayarları PPSSPP varsayılanlarına döndürmek istediğinden emin misin? Resume = Devam ettir Run CPU Tests = İşlemci testlerini başlat -Save language ini = Dil Dosyası Kaydet (.ini) Save new textures = Yeni dokuları kaydet Shader Viewer = Shader Görüntüleyici Show Developer Menu = Geliştirici Menüsünü Göster @@ -320,6 +315,8 @@ Load completed = Yükleme tamamlandı. Loading = Yükleniyor\nLütfen Bekleyin... LoadingFailed = Veri yüklenemedi. Move = Taşı +Move Down = Move Down +Move Up = Move Up Network Connection = Ağ Bağlantısı NEW DATA = YENİ VERİ No = Hayır @@ -327,6 +324,7 @@ ObtainingIP = IP adresi alınıyor.\nLütfen bekleyin... OK = Tamam Old savedata detected = Eski kayıt bulundu. Options = Ayarlar +Remove = Remove Reset = Sıfırla Resize = Yeniden Boyutlandır Retry = Yeniden Dene @@ -462,6 +460,8 @@ Aggressive = Agresif Alternative Speed = Alternatif Hız (% 0 = sınırsız) Alternative Speed 2 = Alternatif Hız 2 (% 0 = sınırsız) Anisotropic Filtering = Anizotropik filtreleme +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Otomatik Auto (1:1) = Otomatik (1:1) Auto (same as Rendering) = Otomatik (İşleme Çözünürlüğüyle Aynı) @@ -471,11 +471,8 @@ Auto Scaling = Otomatik ölçekleme Backend = Arkauç Balanced = Dengeli Bicubic = Çift Kübik -BlockTransfer Tip = Bazı oyunlarda doğru grafikler için bu ayarın açık olması gerekir -BlockTransferRequired = Uyarı: Bu oyun Blok Aktarım Simülasyon Modunun Açık olmasını gerektirir. Both = İkisi de Buffer graphics commands (faster, input lag) = Grafik komutlarını arabellekle (daha hızlı, input lag'e sebep olabilir) -Buffered Rendering = Yükleyerek işleme BufferedRenderingRequired = Uyarı: Bu oyun "işleme modunun" "yükleyerek işleme"ye alınmasını gerektirir. Camera = Kamera Camera Device = Kamera cihazı @@ -493,16 +490,16 @@ Device = Cihaz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Devre dışı -Display layout editor = Görüntü Düzeni Düzenleyicisi +Display Layout && Effects = Görüntü Düzeni Düzenleyicisi Display Resolution (HW scaler) = Görüntü Çözünürlüğü (HW scaler) -Dump next frame to log = Sonraki kareyi günlüğe dökümle Enable Cardboard VR = Cardboard VR'ı Etkinleştirin FPS = FPS Frame Rate Control = Kare hızı denetimi Frame Skipping = Kare atla Frame Skipping Type = Kare atlama türü FullScreen = Tam ekran -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Hack ayarları (Küçük teknik problemlere neden olabilir.) Hardware Tessellation = Donanım Mozaikleme Hardware Transform = Donanım dönüştürme @@ -527,7 +524,7 @@ Must Restart = Bu değişikliğin uygulanması için PPSSPP'yi yeniden başlatma Native device resolution = Yerel aygıt çözünürlüğü Nearest = En yakın No buffer = Arabellek/tampon bellek yok -Non-Buffered Rendering = Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) +Skip Buffer Effects = Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) None = Hiçbiri Number of Frames = Kare sayısı Off = Kapalı @@ -536,28 +533,27 @@ Overlay Information = Ek Bilgi Partial Stretch = Tam ekran (kısmi sünme) Percent of FPS = FPS yüzdesi Performance = Performans -Postprocessing effect = Postprocessing efektleri -Postprocessing Shader = Postprocessing gölgelendiricisi +Postprocessing shaders = Postprocessing gölgelendiricisi Recreate Activity = Recreate activity Render duplicate frames to 60hz = Yinelenen kareleri 60Hz'de işleyin RenderDuplicateFrames Tip = Daha düşük kare hızlarında çalışan oyunlarda kare hızını düzeltebilir Rendering Mode = İşleme modu Rendering Resolution = İşleme çözünürlüğü RenderingMode NonBuffered Tip = Daha hızlıdır, ancak bazı oyunlarda hiçbir şey çizilmeyebilir -Retain changed textures = Değişen dokuları koruyun (bazen daha yavaştır) -RetainChangedTextures Tip = Çoğu oyunu yavaşlatır ama bazı oyunları çok hızlandırır. Rotation = Rotasyon Safe = Güvenli -Screen layout = Ekran düzeni Screen Scaling Filter = Ekran ölçekleme filtresi Show Debug Statistics = Hata ayıklama istatistiklerini göster Show FPS Counter = FPS sayacını göster -Simulate Block Transfer = Blok aktarım efektlerini simüle edin +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Yazılımsal işleme (Deneysel) Software Skinning = Software skinning SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games Speed = Hız -Stretching = Serbest tam ekran (sünme) +Speed Hacks = Hız Hacks (Küçük teknik problemlere neden olabilir.) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Serbest tam ekran (sünme) Texture Filter = Doku filtreleme Texture Filtering = Doku filtreleme Texture Scaling = Doku ölçekleme @@ -602,7 +598,7 @@ You can press ESC to cancel. = İptal etmek için Esc'ye basabilirsiniz. [MainMenu] Browse = Aç... -Buy PPSSPP Gold = Buy PPSSPP Gold +Buy PPSSPP Gold = PPSSPP Gold'u Al Choose folder = Klasör seç Credits = Emeği Geçenler PPSSPP Homebrew Store = PPSSPP Bağımsız Yapım Mağazası @@ -630,7 +626,7 @@ Audio = Ses Controls = Kontroller Graphics = Grafik Networking = Ağ ayarları -Search = Search +Search = Ara System = Sistem Tools = Araçlar @@ -771,13 +767,13 @@ Enable built-in PRO Adhoc Server = Yerleşik PRO Ad Hoc Sunucusunu etkinleştir Enable network chat = Ağ sohbetini etkinleştir Enable networking = Ağ Oluşturma/WLAN'ı aç (Henüz Beta, oyun çökebilir.) Enable UPnP = UPnP'yi etkinleştirin (algılamak için birkaç saniye gerekir) -EnableQuickChat = Hızlı chat'i etkinleştirin +EnableQuickChat = Hızlı sohbeti etkinleştirin Enter a new PSP nickname = Yeni bir PSP kullanıcı adı girin -Enter Quick Chat 1 = Hızlı chat 1'e girin -Enter Quick Chat 2 = Hızlı chat 2'ye girin -Enter Quick Chat 3 = Hızlı chat 3'e girin -Enter Quick Chat 4 = Hızlı chat 4'e girin -Enter Quick Chat 5 = Hızlı chat 5'e girin +Enter Quick Chat 1 = Hızlı sohbet 1'e girin +Enter Quick Chat 2 = Hızlı sohbet 2'ye girin +Enter Quick Chat 3 = Hızlı sohbet 3'e girin +Enter Quick Chat 4 = Hızlı sohbet 4'e girin +Enter Quick Chat 5 = Hızlı sohbet 5'e girin Error = Hata Failed to Bind Localhost IP = Failed to bind localhost IP Failed to Bind Port = Failed to bind port @@ -794,11 +790,11 @@ Please change your Port Offset = Lütfen Port Offset'i değiştirin Port offset = Port offset(0 = PSP uyumluluğu) Open PPSSPP Multiplayer Wiki Page = PPSSPP Ad-Hoc Wiki Sayfası proAdhocServer Address: = Ad hoc sunucu adresi: -Quick Chat 1 = Hızlı chat 1 -Quick Chat 2 = Hızlı chat 2 -Quick Chat 3 = Hızlı chat 3 -Quick Chat 4 = Hızlı chat 4 -Quick Chat 5 = Hızlı chat 5 +Quick Chat 1 = Hızlı sohbet 1 +Quick Chat 2 = Hızlı sohbet 2 +Quick Chat 3 = Hızlı sohbet 3 +Quick Chat 4 = Hızlı sohbet 4 +Quick Chat 5 = Hızlı sohbet 5 QuickChat = Hızlı sohbet Send = Gönder Send Discord Presence information = Discord "Rich Presence" bilgisi gönder @@ -829,9 +825,9 @@ Undo last load = Son yüklemeyi geri al Undo last save = Son kaydetmeyi geri al [PostShaders] (duplicated setting, previous slider will be used) = (yinelenen ayar, önceki kaydırıcı kullanılacaktır) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Miktar Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -841,22 +837,25 @@ Brightness = Parlaklık Cartoon = Çizgi film CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Karşıtlık CRT = CRT tarama çizgileri FXAA = FXAA Kenar Yumuşatma Gamma = Gamma -Grayscale = Gri tonlama +GreenLevel = Green level Intensity = Yoğunluk -InverseColors = Ters Renkler +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Doğal Renkler NaturalA = Doğal Renkler (bulanıklık yok) Off = Kapalı Power = Güç PSPColor = PSP rengi +RedBlue = Red/Blue glasses Saturation = Doygunluk Scanlines = Tarama Çizgileri (CRT) Sharpen = Keskinleştir +SideBySide = Side by side (SBS) SSAA(Gauss) = Süper örneklemeli Kenar Yumuşatma (Gauss) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -868,8 +867,8 @@ Vignette = Vinyet all the forum mods = Bütün forum modlarına build server = build server Buy Gold = Altın Sürümü alın -check = Ayrıca Etraftaki En İyi Wii/GC Emülatörü Olan Dolphin'e Gözatın: -CheckOutPPSSPP = Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/ +check = Ayrıca etraftaki en iyi Wii/GC emülatörü olan Dolphin'e göz atın: +CheckOutPPSSPP = PPSSPP'ye göz atın: https://www.ppsspp.org/ contributors = Yardımcılar: created = Yaratıcı Discord = Discord @@ -877,18 +876,18 @@ info1 = PPSSPP sadece eğitimsel amaçlar için tasarlandı. info2 = Lütfen oynadığınız herhangi bir oyunun haklarına sahip olduğunuzu, info3 = oyunun UMD'sini veya PSP'niz üzerinden info4 = PSN Store'dan dijital sürümünü satın alarak emin olunuz. -info5 = PSP SONY'nin tescilli markasıdır. -iOS builds = iOS builds +info5 = PSP, Sony'nin tescilli markasıdır. +iOS builds = iOS derlemeleri license = GPL 2.0+ altında bir "özgür yazılım" list = Uyumluluk Listeleri, Forumlar ve Geliştirme Bilgisi PPSSPP Forums = PPSSPP Forumları -Privacy Policy = Privacy policy +Privacy Policy = Gizlilik politikası Share PPSSPP = PPSSPP'yi Paylaş specialthanks = Özel Teşekkürler: specialthanksKeithGalocy = at NVIDIA (hardware, advice) specialthanksMaxim = for his amazing Atrac3+ decoder work -testing = testing -this translation by = Türkçe Çeviri Yapan: +testing = test +this translation by = Türkçe çeviri: title = Hızlı ve Taşınabilir PSP Emülatörü tools = Kullanılan Ücretsiz Araçlar: # Add translators or contributors who translated PPSSPP into your language here. @@ -896,12 +895,12 @@ tools = Kullanılan Ücretsiz Araçlar: # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = Gravityy translators2 = mygizli04 -translators3 = kishiradarken1867 +translators3 = Kyria Crown translators4 = translators5 = translators6 = -Twitter @PPSSPP_emu = Twitter @PPSSPP_emu -website = PPSSPP.org'u Ziyaret Et +Twitter @PPSSPP_emu = Twitter +website = PPSSPP.org written = Hız ve Taşınabilirlik için C++ ile Yazıldı [RemoteISO] @@ -935,7 +934,7 @@ FeedbackIncludeCRC = Not: Batarya diskin döngüsel artıklık denetimini yollam FeedbackIncludeScreen = Ekran görüntüsü dahil et FeedbackSubmitDone = Veriniz gönderildi. FeedbackSubmitFail = Veri sunucuya gönderilemedi. PPSSPP'yi güncellemeyi deneyin. -FeedbackThanks = Geribildirimin için teşekkürler! +FeedbackThanks = Geribildiriminiz için teşekkürler! Gameplay = Oynanış Graphics = Grafikler Great = İyi @@ -958,20 +957,20 @@ Speed = Hız Submit Feedback = Geribildirimi yolla SuggestionConfig = İyi ayarlar için sitedeki ayarlara bakın. SuggestionCPUSpeed0 = Kilitlenmiş CPU hızını kapat. -SuggestionDowngrade = Daha eski bir PPSSPP sürümüne indirin ( Bu bugu rapor edin, lütfen. ) -SuggestionsFound = Diğer kullanıcılar daha iyi sonuçlar rapor etti. Daha fazla ayrıntı için "Geri dönüşü görüntüle" tuşuna basın. +SuggestionDowngrade = Daha eski bir PPSSPP sürümüne indirin (Lütfen bu hatayı raporlayın.) +SuggestionsFound = Diğer kullanıcılar daha iyi sonuçlar raporladı. Daha fazla ayrıntı için "Geribildirimi görüntüle"ye basın. SuggestionsNone = Bu oyun diğer kullanıcılar için de çalışmıyor. SuggestionsWaiting = Gönderiliyor ve diğer kullanıcıların da sonuçlarına bakılıyor... SuggestionUpgrade = Daha yeni bir PPSSPP sürümüne güncelleyin. SuggestionVerifyDisc = ISO dosyanızın doğru olduğunu kontrol edin. -Unselected Overall Description = Bu oyun nasıl simule ediliyor? +Unselected Overall Description = Bu oyun nasıl simüle ediliyor? View Feedback = Bütün geribildirimleri göster [Savedata] -Date = Date +Date = Tarih Filename = Dosya adı No screenshot = Ekran görüntüsü yok -None yet. Things will appear here after you save. = Henüz birşey yok.Kayıt aldığında kayıtların burada gözükecek. +None yet. Things will appear here after you save. = Henüz bir şey yok. Kayıt aldığında kayıtların burada görünecek. Nothing matching '%1' was found. = '%1' ile eşleşen hiçbir şey bulunamadı. Save Data = Normal Kayıtlar Save States = Durum Kayıtları @@ -986,7 +985,7 @@ Failed to load state = Durum yüklenemedi. Failed to save state = Durum kaydedilemedi. fixed = Hız: Alternatif GLToolsWarning = UYARI: GLTools algılandı, problemlere sebep olabilir. -In menu = In menu +In menu = Menüde Load savestate failed = Durum kaydı yüklenemedi. Loaded State = Durum yüklendi. Loaded. Game may refuse to save over different savedata. = Yüklendi. Oyun belki farklı verilerin üzerine kaydetmeyi reddedebilir. @@ -996,7 +995,7 @@ LoadStateDoesntExist = Durum yüklenemedi: Durum kaydı yerinde yok! LoadStateWrongVersion = Durum yüklenemedi: Durum kaydı eski bir PPSSPP versiyonu için uygun! norewind = Geriye sarma durumu bulunamadı. Playing = Oynatılıyor... -PressESC = PPSSPP menüsünü açmak için ESC'ye bas. +PressESC = PPSSPP menüsünü açmak için ESC'ye basın. replaceTextures_false = Dokular artık değiştirilmiyor. replaceTextures_true = Doku değiştirme etkinleştirildi. Save State Failed = Durum kaydı yapılamadı! @@ -1009,11 +1008,11 @@ State load undone = Durum yüklemesi tamamlanmadı Untitled PSP game = Başlıksız PSP oyunu [Search] -Clear filter = Clear filter -Filter = Filter -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -No settings matched '%1' = No settings matched '%1' +Clear filter = Filtreyi temizle +Filter = Filtre +Filtering settings by '%1' = Ayarlar '%1''e göre filtreleniyor +Find settings = Ayarları ara +No settings matched '%1' = '%1' ile eşleşen ayar yok [Store] Already Installed = Zaten yüklü @@ -1026,8 +1025,10 @@ Size = Boyut Uninstall = Sil [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (çekirdek başına %d , %d çekirdek ) %d bytes = %d bayt +%d Hz = %d Hz (none detected) = (hiç bulunamadı) 3D API = 3D API ABI = ABI @@ -1045,11 +1046,12 @@ CPU Name = Ad D3DCompiler Version = D3DCompiler sürümü Debug = Hata Ayıklama Debugger Present = Hata ayıklayıcı var +Depth buffer format = Depth buffer format Device Info = Cihaz bilgisi Directories = Dizinler -Display Color Formats = Display Color Formats +Display Color Formats = Renk Biçimlerini Görüntüle Display Information = Ekran bilgisi -Driver bugs = Driver bugs +Driver bugs = Sürücü hataları Driver Version = Sürücü sürümü EGL Extensions = EGL eklentileri Frames per buffer = Tampon başına çerçeveler @@ -1058,19 +1060,19 @@ High precision float range = High precision float range High precision int range = High precision int range Lang/Region = Dil/Bölge Memory Page Size = Bellek sayfa boyutu -Native Resolution = Doğal çözünürlük -No GPU driver bugs detected = No GPU driver bugs detected +Native Resolution = Yerel çözünürlük +No GPU driver bugs detected = GPU sürücü hatası algılanmadı OGL Extensions = OGL eklentileri OpenGL ES 2.0 Extensions = OpenGL ES 2.0 eklentileri OpenGL ES 3.0 Extensions = OpenGL ES 3.0 eklentileri OpenGL Extensions = OpenGL eklentileri Optimal frames per buffer = Optimum tampon başına çerçeveler Optimal sample rate = Optimum örnekleme hızı -OS Information = İS bilgisi +OS Information = İşletim sistemi bilgisi PPSSPP build = PPSSPP derlemesi Refresh rate = Yenileme hızı Release = Release -RW/RX exclusive = RW/RX 'e özel +RW/RX exclusive = RW/RX'e özel Sample rate = Örnekleme hızı Shading Language = Gölgelendirme dili Storage = Depolama @@ -1079,8 +1081,8 @@ System Information = Sistem bilgisi System Name = Ad System Version = Sistem sürümü Threads = İzlekler -Vendor = Satıcı -Vendor (detected) = Satıcı (tespit edildi) +Vendor = Üretici +Vendor (detected) = Üretici (tespit edildi) Version Information = Sürüm bilgisi Vulkan Extensions = Vulkan eklentileri Vulkan Features = Vulkan özellikleri @@ -1091,15 +1093,17 @@ Vulkan Features = Vulkan özellikleri 24HR = 24 saat Auto = Otomatik Auto Load Savestate = Otomatik durum kaydı yükle -AVI Dump started. = AVI kaydı başladı -AVI Dump stopped. = AVI kaydı bitti +AVI Dump started. = AVI kaydı başladı. +AVI Dump stopped. = AVI kaydı bitti. Cache ISO in RAM = Bütün ISO'yu RAM'e önbellekle Change CPU Clock = Taklit edilen PSP'nin CPU sayacını değiştir (kararsız) -Color Saturation = Color Saturation -Color Tint = Color Tint +Color Saturation = Renk Doygunluğu +Color Tint = Renk Tonu Error: load undo state is from a different game = Hata: yükleme geri alma durumu farklı bir oyundan Failed to load state for load undo. Error in the file system. = Yüklemeyi geri alma durumu yüklenemedi. Dosya sisteminde hata. -Floating symbols = kayan simgeler +Floating symbols = Kayan simgeler +Game crashed = Game crashed +Language = Dil Memory Stick folder = Hafıza Kartı klasörü Memory Stick size = Hafıza Kartı boyutu Change Nickname = Kullanıcı adını değiştir @@ -1116,12 +1120,12 @@ DDMMYYYY = GGAAYYYY Decrease size = Boyutu küçült Developer Tools = Geliştirici araçları Display Extra Info = Fazladan bilgileri göster -Display Games on a grid = "Oyunlar"ı bir ızgarada göster -Display Homebrew on a grid = "Bağımsız Yapımlar && Demolar"ı bir ızgarada göster -Display Recent on a grid = "Geçmiş"i bir ızgarada göster +Display Games on a grid = Oyunları ızgarada göster +Display Homebrew on a grid = Demolar && Bağımsız Yapımları ızgarada göster +Display Recent on a grid = Geçmişi ızgarada göster Dynarec (JIT) = Dynarec (JIT) Emulation = Emülasyon -Enable Cheats = Hileleri aç +Enable Cheats = Hileleri etkinleştir Enable Compatibility Server Reports = Uyumluluk sunucusu raporlarını etkinleştir Failed to load state. Error in the file system. = Durum yüklenemedi. Dosya sistemi hatası. Failed to save state. Error in the file system. = Durum kaydedilemedi. Dosya sistemi hatası. @@ -1137,7 +1141,7 @@ Host (bugs, less lag) = Host (buglu, daha az kasma) Ignore bad memory accesses = Kötü bellek erişimlerini yoksay Increase size = Boyutu arttır Interpreter = Tercüman -IO timing method = G / Ç zamanlama yöntemi +IO timing method = G/Ç zamanlama yöntemi IR Interpreter = IR tercümanı Memory Stick Folder = Hafıza Kartı klasörü Memory Stick inserted = Hafıza kartı takıldı @@ -1160,15 +1164,15 @@ Record Audio = Sesi kaydet Record Display = Görüntüyü kaydet Reset Recording on Save/Load State = Kaydet/Yükle durumunda kaydı sıfırla Restore Default Settings = Varsayılan ayarları yükle -Rewind Snapshot Frequency = Geri sarma görüntüsü sıklılığı (mem hog) +Rewind Snapshot Frequency = Geri sarma görüntüsü sıklığı (mem hog) Save path in installed.txt = Yolu installed.txt'ye kaydet Save path in My Documents = Dosyaları "Belgeler"'e kaydet Savestate Slot = Durum kaydı yeri Savestate slot backups = Durum kaydı slot yedekleri -Screenshots as PNG = Ekran görüntülerini PNG formatında kaydet +Screenshots as PNG = Ekran görüntülerini PNG olarak kaydet Set UI background... = Arayüz arkaplanı ayarla... Show ID = ID'yi göster -Show Memory Stick folder = Show Memory Stick folder +Show Memory Stick folder = Hafıza Kartı klasörünü göster Show region flag = Bölge bayrağını göster Simulate UMD delays = UMD gecikmelerini simule et Slot 1 = Slot 1 @@ -1178,21 +1182,21 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Depolama dolu Sustained performance mode = Sürekli performans modu -Theme = Theme +Theme = Tema Time Format = Zaman biçimi UI = Kullanıcı arayüzü UI background animation = UI arka plan animasyonu UI Sound = UI sesi undo %c = %c 'yi yedekle USB = USB -Use Lossless Video Codec (FFV1) = Kayıpsız video kodek'i kullan (FFV1) +Use Lossless Video Codec (FFV1) = Kayıpsız video codec'i kullan (FFV1) Use O to confirm = O (Japonya) Use output buffer (with overlay) for recording = Kayıt için çıktı arabelleğini kullanın (bindirmeli) Use system native keyboard = Sistem yerel klavyesini kullan Use X to confirm = X (Küresel) VersionCheck = Güncellemeleri denetle -WARNING: Android battery save mode is on = UYARI: Android güç tasaruufu açık -WARNING: Battery save mode is on = UYARI: Güç tasarrufu açık +WARNING: Android battery save mode is on = UYARI: Android pil tasarrufu açık +WARNING: Battery save mode is on = UYARI: Pil tasarrufu açık Waves = Dalgalar YYYYMMDD = YYYYAAGG @@ -1203,21 +1207,35 @@ Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ [Themes] -Default = Default +Default = Varsayılan [UI Elements] -%1 button = %1 button -%1 checkbox = %1 checkbox -%1 choice = %1 choice -%1 heading = %1 heading -%1 radio button = %1 radio button -%1 text field = %1 text field -Choices: = Choices: -List: = List: +%1 button = %1 düğmesi +%1 checkbox = %1 onay kutusu +%1 choice = %1 seçeneği +%1 heading = %1 başlığı +%1 radio button = %1 radyo düğmesi +%1 text field = %1 metin alanı +Choices: = Seçenekler: +List: = Liste: Progress: %1% = Progress: %1% -Screen representation = Screen representation +Screen representation = Ekran gösterimi [Upgrade] Details = Detaylar Dismiss = Reddet Download = İndir New version of PPSSPP available = PPSSPP'nin yeni versiyonu mevcut + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index b6ec199493..2d60d05558 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -129,7 +129,6 @@ Backend = Бекенд &рендерингу (потрібне перезава Bicubic = &Бікубічний Break = Перервати Break on Load = Перервати при завантаженні -Buffered Rendering = Буферинізований рендеринг Buy Gold = Купити &Gold Control Mapping... = Призначення &кнопок... Debugging = &Налагодження @@ -138,7 +137,7 @@ Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = &Розбирання... Discord = Discord -Display Layout Editor = Редактор розташування екрану... +Display Layout && Effects = Редактор розташування екрану... Display Rotation = Орієнтація екрану Dump Next Frame to Log = Зберегти &кадр у лог Emulation = &Емуляція @@ -173,7 +172,7 @@ Log Console = Консоль журналу (log) Memory View... = Переглядач па&м'яті... More Settings... = &Ще налаштування... Nearest = &Найближчий -Non-Buffered Rendering = &Пропустити ефекти (небуферований, швидше) +Skip Buffer Effects = &Пропустити ефекти (небуферований, швидше) Off = В&имкнено Open Chat = Open Chat Open Directory... = Відкрити &папку... @@ -185,7 +184,6 @@ Pause = &Пауза Pause When Not Focused = &Пауза коли вікно не в фокусі Portrait = Портретне Portrait reversed = Портретна (перевернуто) -Postprocessing Shader = &Подальша обробка (шейдер) PPSSPP Forums = &Форум PPSSPP Record = &Запис Record Audio = Запис &аудіо @@ -233,7 +231,7 @@ DevMenu = Меню розроб. Disabled JIT functionality = Вимкнений функціонал JIT Draw Frametimes Graph = Намалюйте графік фрагментів Dump Decrypted Eboot = Дамп дешифрування Eboot.bin при паузі -Dump Frame GPU Commands = Дамп команд GPU кадру +Dump next frame to log = Зберегти кадр у лог Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Ввімкнути логування Enter address = Введіть адресу @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Профілі кадрів GPU Driver Test = Перевірка драйверу GPU -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = Профіль GPU Jit Compare = Порівняння з Jit JIT debug tools = Інструменти налагодження JIT -Language = Мова -Load language ini = Завантажити мовний .ini файл Log Dropped Frame Statistics = Лог статистики пропущених кадрів Log Level = Лог рівня Log View = Лог виду @@ -262,7 +258,6 @@ RestoreDefaultSettings = "Ви впевненні,що хочете скинут RestoreGameDefaultSettings = Ви впевнені, що хочете повернути всі параметри гри до стардартних\nповернути PPSSPP за замовчуванням ? Resume = Resume Run CPU Tests = Запустити тести CPU -Save language ini = Зберегти мовний .ini файл Save new textures = Зберегти нові текстури Shader Viewer = Переглядач шейдеру Show Developer Menu = Показати меню розробника @@ -318,6 +313,8 @@ Load completed = Завантаження завершене Loading = Завантаження\nБудь ласка, зачекайте... LoadingFailed = Не вдалося завантажити дані. Move = Положення +Move Down = Move Down +Move Up = Move Up Network Connection = Підключення до мережі NEW DATA = Нове збереження No = Ні @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Виявлено старий формат збережень Options = Опції: +Remove = Remove Reset = Скинути Resize = Розмір Retry = Повторити @@ -460,6 +458,8 @@ Aggressive = Примусово Alternative Speed = Альтернативна шв. (к %, 0 = необмежено) Alternative Speed 2 = Альтернативна шв. 2 (к %, 0 = необмежено) Anisotropic Filtering = Анізотропна фільтрація +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Авто Auto (1:1) = Авто (1:1) Auto (same as Rendering) = Авто (таке ж як розширення рендерингу) @@ -469,11 +469,8 @@ Auto Scaling = Автоматичне масштабування Backend = Бекенд Balanced = Збалансовано Bicubic = Бікубічний -BlockTransfer Tip = Потрібно для правильної графіки в деяких іграх -BlockTransferRequired = Попередження: Ця гра вимагає, щоб "імітувати ефекти передачі блоку" було встановлено на Увімкнено. Both = Обидва Buffer graphics commands (faster, input lag) = Буферні графічні команди (швидше, можливі глюки) -Buffered Rendering = Буферинізований рендеринг BufferedRenderingRequired = Попередження: Ця гра вимагає, щоб "режим візуалізації" був встановлений на "буферний". Camera = Камера Camera Device = Пристрій камери @@ -491,16 +488,16 @@ Device = Пристрій Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Вимкнено -Display layout editor = Редактор розташування екрану +Display Layout && Effects = Редактор розташування екрану Display Resolution (HW scaler) = Розширення екрану (HW масштабування) -Dump next frame to log = Зберегти кадр у лог Enable Cardboard VR = Увімкнути Cardboard VR FPS = FPS Frame Rate Control = Управління частотою кадрів Frame Skipping = Пропуск кадрів Frame Skipping Type = Тип пропуску кадрів FullScreen = Повноекранний режим -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Параметри хаків (можуть викликати глюки) Hardware Tessellation = Апаратна тесселляція Hardware Transform = Апаратне перетворення @@ -525,7 +522,7 @@ Must Restart = Ви повинні перезавантажити PPSSPP, щоб Native device resolution = Роздільна здатність пристрою Nearest = Найближчий No buffer = Без буфера -Non-Buffered Rendering = Пропускати ефекти (небуференізованний, швидше) +Skip Buffer Effects = Пропускати ефекти (небуференізованний, швидше) None = Немає Number of Frames = Кількість кадрів Off = Вимкнено @@ -534,28 +531,27 @@ Overlay Information = Інформація про накладення Partial Stretch = Часткове розтягнення Percent of FPS = Відсоток FPS Performance = Продуктивність -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Шейдери +Postprocessing shaders = &Подальша обробка (шейдер) Recreate Activity = Відтворити діяльність Render duplicate frames to 60hz = Відображення повторюваних кадрів до 60 Гц RenderDuplicateFrames Tip = Можна зробити більш плавний кадр в іграх, які працюють у нижчих кадрах Rendering Mode = Режим рендерингу Rendering Resolution = Розширення рендерингу RenderingMode NonBuffered Tip = Швидше, але в деяких іграх нічого не може -Retain changed textures = Зберігати змінені текстури (іноді повільніше) -RetainChangedTextures Tip = Багато ігор робить повільніше, але деякі ігри набагато швидшими Rotation = Орієнтація: Safe = Безпечно -Screen layout = Screen layout Screen Scaling Filter = Фільтр обчислення екрану Show Debug Statistics = Відоброжати зневадження Show FPS Counter = Показати FPS -Simulate Block Transfer = Симулювати ефекти від передачі блоків +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Програмний рендеринг (експериментально) Software Skinning = Програмна заливка SoftwareSkinning Tip = Комбінована модель розібраної моделі яка притягується до процесора, швидше в більшості ігор Speed = Швидкість -Stretching = Розтягнення +Speed Hacks = Speed Hacks (можуть викликати глюки) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Розтягнення Texture Filter = Фільтр текстур Texture Filtering = Фільтрація текстур Texture Scaling = Масштабування текстур @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Кольори Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Яскравість Cartoon = Мультиплікація CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Корекція кольорів +ColorPreservation = Color preservation Contrast = Контраст CRT = Кінескоп 1 FXAA = FXAA згладжування Gamma = Гамма -Grayscale = Відтінки сірого +GreenLevel = Green level Intensity = Інтенсивність -InverseColors = Зворотні кольори +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Натуральні кольори NaturalA = Натуральні кольори (без розмиття) Off = Вимкнені Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Насиченість Scanlines = Кінескоп 2 Sharpen = Різкість +SideBySide = Side by side (SBS) SSAA(Gauss) = SSAA (Гаусс) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Розмір Uninstall = Видалити [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d на ядро, ядер: %d) %d bytes = %d байт +%d Hz = %d Hz (none detected) = (не виявлено) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Назва D3DCompiler Version = Версія D3DCompiler Debug = Налагодження Debugger Present = Присутній налагоджувач +Depth buffer format = Depth buffer format Device Info = Інформація про пристрій Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Мова Memory Stick folder = Змінити папку для карти пам'яті Memory Stick size = Memory Stick size Change Nickname = Змінити ім'я @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Відхилити Download = Завантажити New version of PPSSPP available = Доступна нова версія PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 40e6bb7b30..8b3c2aa73e 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -129,7 +129,6 @@ Backend = Kết xuất từ thư viện đồ họa (Khởi động lại PPSSPP Bicubic = Bicubic (mịn) Break = Break Break on Load = Hủy bỏ trong mục load -Buffered Rendering = Dựng hình có bộ nhớ đệm Buy Gold = Mua PPSSPP Gold Control Mapping... = Chỉnh nút... Debugging = Debug @@ -138,7 +137,7 @@ Direct3D9 = Direct3D9 Direct3D11 = Direct3D11 Disassembly = Disassembly (Tháo gỡ)... Discord = Discord -Display Layout Editor = Hiện nút chỉnh sửa bố cục... +Display Layout && Effects = Hiện nút chỉnh sửa bố cục... Display Rotation = Hiện nút xoay màn hình Dump Next Frame to Log = Dump Next Frame to Log Emulation = Giả lập @@ -173,7 +172,7 @@ Log Console = Log Console Memory View... = Xem bộ nhớ... More Settings... = Các thiết lập khác... Nearest = Gần nhất -Non-Buffered Rendering = Bỏ qua hiệu ứng đệm (Không bộ nhớ đệm, nhanh hơn) +Skip Buffer Effects = Bỏ qua hiệu ứng đệm (Không bộ nhớ đệm, nhanh hơn) Off = Tắt Open Chat = Open Chat Open Directory... = Mở thư mục... @@ -185,7 +184,6 @@ Pause = Tạm dừng Pause When Not Focused = Dừng trò chơi khi "ko tập trung" Portrait = Chiều dọc Portrait reversed = Chiều dọc đảo ngược -Postprocessing Shader = Xử lý hậu đổ bóng PPSSPP Forums = Diễn đàn PPSSPP Record = Ghi lại Record Audio = Ghi âm thanh @@ -233,7 +231,7 @@ DevMenu = Menu NPH Disabled JIT functionality = Disabled JIT functionality Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Đưa file vào EBOOT.BIN để khởi động trò chơi -Dump Frame GPU Commands = Đưa lệnh vào khung GPU +Dump next frame to log = Đưa khung hình kế tiếp vào nhật ký Enable driver bug workarounds = Enable driver bug workarounds Enable Logging = Cho phép ghi nhật ký debug Enter address = Nhập địa chỉ @@ -241,12 +239,10 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Khung hồ sơ GPU Driver Test = GPU driver test -GPU Log Profiler = GPU Log Profiler +GPU log profiler = GPU log profiler GPU Profile = GPU profile Jit Compare = So sánh Jit JIT debug tools = JIT debug tools -Language = Ngôn ngữ -Load language ini = Tải file ngôn ngữ .ini Log Dropped Frame Statistics = Khung nhật ký thống kê Log Level = Cấp nhật ký Log View = Xem nhật ký @@ -262,7 +258,6 @@ RestoreDefaultSettings = Bạn có muốn khôi phục các thiết lập về m RestoreGameDefaultSettings = Bạn có muốn khôi phục cài đặt trò chơi\nPPSSPP sẽ trở về mặc định? Resume = Resume Run CPU Tests = Chạy thử CPU -Save language ini = Lưu file ngôn ngữ .ini Save new textures = Lưu file textures mới Shader Viewer = Xem trước đỗ bóng Show Developer Menu = Hiện menu NPH @@ -318,6 +313,8 @@ Load completed = Đã load xong. Loading = Đang load\nXin đợi... LoadingFailed = Không thể load dữ liệu này. Move = Di chuyển +Move Down = Move Down +Move Up = Move Up Network Connection = Kết nối mạng NEW DATA = DỮ LIỆU MỚI No = Không @@ -325,6 +322,7 @@ ObtainingIP = Obtaining IP address.\nPlease wait... OK = OK Old savedata detected = Phát hiện dữ liệu cũ Options = Tùy chọn +Remove = Remove Reset = Mặc định Resize = Thay đổi kích thước Retry = Thử lại @@ -460,6 +458,8 @@ Aggressive = Xâm lược Alternative Speed = Tốc độ luân phiên Alternative Speed 2 = Tốc độ luân phiên 2 (trong %, 0 = không giới hạn) Anisotropic Filtering = Lọc không cùng hướng +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio Auto = Tự động Auto (1:1) = Tự động (1:1) Auto (same as Rendering) = Tự động (cùng với kết xuất) @@ -469,11 +469,8 @@ Auto Scaling = Tự động nhân rộng Backend = Thư viện đồ họa Balanced = Cân bằng Bicubic = Bicubic (mịn) -BlockTransfer Tip = Một số trò chơi yêu cầu đồ họa thích hợp. -BlockTransferRequired = Cảnh báo: Trò chơi này yêu cầu mở "simulate block transfer effects" Both = Cả hai Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) -Buffered Rendering = Dựng hình có bộ nhớ đệm BufferedRenderingRequired = Cảnh báo: Trò chơi này yêu cầu "chế độ kết xuất" được đặt thành "được đệm". Camera = Camera Camera Device = Camera device @@ -491,16 +488,16 @@ Device = Thiết bị Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Vô hiệu hóa -Display layout editor = Chỉnh bố trí hiển thị +Display Layout && Effects = Chỉnh bố trí hiển thị Display Resolution (HW scaler) = Độ phân giải màn hình (HW scaler) -Dump next frame to log = Đưa khung hình kế tiếp vào nhật ký Enable Cardboard VR = Enable Cardboard VR FPS = FPS (khung hình/giây) Frame Rate Control = Điều khiển tốc độ khung hình Frame Skipping = Nhảy khuôn hình Frame Skipping Type = Frame skipping type FullScreen = Toàn màn hình -GPU log profiler = GPU log profiler +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. Hack Settings = Thiết lập hack (sẽ bị lỗi) Hardware Tessellation = Lót phần cứng Hardware Transform = Chuyển đổi phần cứng @@ -525,7 +522,7 @@ Must Restart = Bạn cần khởi động lại PPSSPP để những thay đổi Native device resolution = Độ phân giải tự nhiên. Nearest = Gần nhất No buffer = No buffer -Non-Buffered Rendering = Bỏ qua hiệu ứng đệm (không bộ nhớ đệm, nhanh hơn) +Skip Buffer Effects = Bỏ qua hiệu ứng đệm (không bộ nhớ đệm, nhanh hơn) None = Không Number of Frames = Number of frames Off = Tắt @@ -534,28 +531,27 @@ Overlay Information = Hiển thị thông tin trên màn hình Partial Stretch = Từng phần dãn ra Percent of FPS = Percent of FPS Performance = Hiệu năng -Postprocessing effect = Postprocessing effects -Postprocessing Shader = Xử lý hậu đổ bóng +Postprocessing shaders = Xử lý hậu đổ bóng Recreate Activity = Recreate activity Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = Chế độ kết xuất Rendering Resolution = Độ phân giải kết xuất RenderingMode NonBuffered Tip = Nhanh hơn, nhưng một số trò chơi thì bị lỗi -Retain changed textures = Giữ lại textures (thỉnh thoảng sẽ bị chậm) -RetainChangedTextures Tip = Làm cho một số trò chơi chậm hơn, nhưng cũng có một số trò chơi nhanh hơn. Rotation = Xoay màn hình Safe = An toàn -Screen layout = Screen layout Screen Scaling Filter = Bộ lọc họa tiết rộng Show Debug Statistics = Hiện thông số debug Show FPS Counter = Hiện thông số FPS -Simulate Block Transfer = Mô phỏng truyền tải khối vật thể , hiệu ứng +Skip GPU Readbacks = Skip GPU Readbacks Software Rendering = Dựng hình bằng phần mềm Software Skinning = phủ lớp bằng phần mềm SoftwareSkinning Tip = Mô hình kết hợp vẽ trên CPU, nhanh hơn trong hầu hết các trò chơi Speed = Tốc độ -Stretching = Stretching +Speed Hacks = Tốc độ Hacks (sẽ bị lỗi) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch Texture Filter = Bộ lọc họa tiết Texture Filtering = Lọc texture Texture Scaling = Họa tiết rộng @@ -828,9 +824,9 @@ Undo last save = Undo last save [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-màu Amount = Amount Animation speed (0 -> disable) = Animation speed (0 -> disable) @@ -840,22 +836,25 @@ Brightness = Brightness Cartoon = Hoạt họa CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction +ColorPreservation = Color preservation Contrast = Contrast CRT = CRT đường quét FXAA = Chống răng cưa FXAA Gamma = Gamma -Grayscale = Đen trắng +GreenLevel = Green level Intensity = Intensity -InverseColors = Màu âm bản +LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Màu tự nhiên (mờ) NaturalA = Màu tự nhiên (không mờ) Off = Tắt Power = Power PSPColor = PSP color +RedBlue = Red/Blue glasses Saturation = Saturation Scanlines = Đường nét (CRT) Sharpen = Sắc nét +SideBySide = Side by side (SBS) SSAA(Gauss) = Siêu mẫu AA (cốt) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1025,8 +1024,10 @@ Size = Kích cỡ Uninstall = Gỡ [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (%d per core, %d cores) %d bytes = %d bytes +%d Hz = %d Hz (none detected) = (không phát hiện) 3D API = 3D API ABI = ABI @@ -1044,6 +1045,7 @@ CPU Name = Tên D3DCompiler Version = D3DCompiler version Debug = Debug Debugger Present = Debugger present +Depth buffer format = Depth buffer format Device Info = Thông tin thiết bị Directories = Directories Display Color Formats = Display Color Formats @@ -1099,6 +1101,8 @@ Color Tint = Color Tint Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols +Game crashed = Game crashed +Language = Ngôn ngữ Memory Stick folder = Memory Stick folder Memory Stick size = Memory Stick size Change Nickname = Đổi nickname @@ -1220,3 +1224,17 @@ Details = Details Dismiss = Bỏ qua Download = Tải về New version of PPSSPP available = Đã có phiên bản mới của PPSSPP + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 486a2d5230..b20cabbdfc 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1,5 +1,5 @@ [Audio] -Alternate speed volume = 自定义速度下的音量 +Alternate speed volume = 自定义速度时的音量 Audio backend = 音频引擎(需要重启) Audio Error = 音频错误 AudioBufferingForBluetooth = 蓝牙友好缓冲区(更慢) @@ -40,7 +40,7 @@ Calibrated = 校准后 Calibration = 校准 Circular stick input = 环形摇杆输入 Classic = 传统 -Confine Mouse = 在窗口/显示区域内捕获鼠标 +Confine Mouse = 鼠标固定在窗口/显示区域内 Control Mapping = 按键映射 Custom Key Setting = 自定义键位设置 Customize = 自定义 @@ -64,7 +64,7 @@ Ignore Windows Key = 忽略Windows键 Invert Axes = 轴反转 Invert Tilt along X axis = 沿X轴倾斜反转 Invert Tilt along Y axis = 沿Y轴倾斜反转 -Keep this button pressed when right analog is pressed = 按下右摇杆时保持按下此按钮 +Keep this button pressed when right analog is pressed = 按下右摇杆时长按此按键 Keyboard = 键盘控制设定 L/R Trigger Buttons = L/R扳机按钮 Landscape = 横向 @@ -82,7 +82,7 @@ Portrait = 纵向 Portrait Reversed = 纵向反转 PSP Action Buttons = PSP功能键 Raw input = 原始输入 -Repeat mode = 重复模式 +Repeat mode = 连点模式 Reset to defaults = 重置为默认 Screen aligned to ground = 屏幕水平地面 Screen at right angle to ground = 屏幕垂直地面 @@ -90,8 +90,8 @@ Screen Rotation = 屏幕旋转 seconds, 0 : off = 秒, 0 = 不隐藏 Sensitivity (scale) = 灵敏度(倍率) Sensitivity = 灵敏度 -Shape = 形状 -Show Touch Pause Menu Button = 显示暂停菜单按键 +Shape = 外形 +Show Touch Pause Menu Button = 显示暂停按键 Swipe = 滑动 Swipe sensitivity = 滑动灵敏度 Swipe smoothing = 滑动平滑度 @@ -101,12 +101,12 @@ Tilt Input Type = 重力感应替代按键类型 Tilt Sensitivity along X axis = 沿X轴倾斜灵敏度 Tilt Sensitivity along Y axis = 沿Y轴倾斜灵敏度 To Calibrate = 如需校准, 请保证设备在一个平面上,然后按"校准" -Toggle mode = 切换模式 -Touch Control Visibility = 触摸按键可见性 +Toggle mode = 开关模式(只需按一次) +Touch Control Visibility = 可见的触屏按键 Use custom right analog = 自定义右摇杆用途 Use Mouse Control = 使用鼠标控制 -Visibility = 可见性设定 -Visible = 可见性 +Visibility = 按键显示 +Visible = 是否显示 X = X Y = Y @@ -129,7 +129,6 @@ Backend = 渲染引擎(需要PPSSPP重新启动) (&b) Bicubic = 双三次 (&B) Break = 停止 Break on Load = 载入后停止 -Buffered Rendering = 缓冲渲染 (&B) Buy Gold = 购买黄金版 (&G) Control Mapping... = 按键映射 (&o)... Debugging = 调试 (&D) @@ -138,7 +137,7 @@ Direct3D9 = Direct3D 9 (&9) Direct3D11 = Direct3D11 (&11) Disassembly = 反汇编 (&D)... Discord = Discord -Display Layout Editor = 显示布局编辑器... +Display Layout && Effects = 屏幕布局/滤镜编辑... Display Rotation = 显示旋转 Dump Next Frame to Log = 转储下一帧到日志 (&U) Emulation = 模拟 (&E) @@ -173,19 +172,18 @@ Log Console = 控制台日志 (&L) Memory View... = 查看内存 (&V)... More Settings... = 更多设置 (&M)... Nearest = 邻近取样 (&N) -Non-Buffered Rendering = 跳过缓冲效果(非缓冲, 更快) (&S) +Skip Buffer Effects = 跳过缓冲效果(不缓冲, 更快) (&S) Off = 关闭 (&O) Open Chat = 打开聊天 Open Directory... = 打开路径(&D)... Open from MS:/PSP/GAME... = 从MS:/PSP/GAME处打开 (&p)... Open Memory Stick = 打开记忆棒 (&M) -Open New Instance = 打开新的模拟器进程 +Open New Instance = 打开新的实例 OpenGL = &OpenGL Pause = 暂停 (&P) Pause When Not Focused = 后台运行时自动暂停 (&P) Portrait = 纵向 Portrait reversed = 纵向反转 -Postprocessing Shader = 后处理着色器 (&g) PPSSPP Forums = PPSSPP官方论坛 (&F) Record = 录制 (&R) Record Audio = 录制音频 (&A) @@ -200,7 +198,7 @@ Save Map File... = 保存内存镜像文件 (&S)... Save State = 快速存档 (&a) Save State File... = 保存即时存档 (&S)... Savestate Slot = 即时存档插槽 (&t) -Screen Scaling Filter = 屏幕缩放滤镜 (&e) +Screen Scaling Filter = 屏幕缩放方法 (&e) Show Debug Statistics = 显示调试信息 (&g) Show FPS Counter = 显示FPS计数器 (&F) Skip Number of Frames = 跳过帧的数量 @@ -208,8 +206,8 @@ Skip Percent of FPS = 跳过帧率的百分比 Stop = 停止 (&S) Switch UMD = 切换UMD光盘 Take Screenshot = 屏幕截图 (&T) -Texture Filtering = 纹理过滤方式 (&x) -Texture Scaling = 纹理缩放方式 (&T) +Texture Filtering = 纹理过滤方法 (&x) +Texture Scaling = 纹理缩放方法 (&T) Use Lossless Video Codec (FFV1) = 使用无损视频编解码器(FFV1) (&U) Use output buffer for video = 录制时使用输出缓冲 Vertex Cache = 顶点缓存 (&V) @@ -233,7 +231,7 @@ DevMenu = 开发者菜单 Disabled JIT functionality = 已禁用的JIT功能 Draw Frametimes Graph = 显示帧时间统计图 Dump Decrypted Eboot = 当载入游戏时转储已解密的EBOOT.BIN -Dump Frame GPU Commands = 转储帧GPU命令 +Dump next frame to log = 转储下一帧到日志 Enable driver bug workarounds = 启用驱动程序错误解决方法 Enable Logging = 启用调试日志 Enter address = 输入地址 @@ -241,16 +239,14 @@ FPU = FPU Framedump tests = 帧转储测试 Frame Profiler = 帧分析器 GPU Driver Test = GPU驱动程序测试 -GPU Log Profiler = GPU日志分析器 +GPU log profiler = GPU日志分析器 GPU Profile = GPU分析器 Jit Compare = Jit比较 JIT debug tools = JIT调试工具 -Language = 语言设置 -Load language ini = 载入语言配置 Log Dropped Frame Statistics = 记录丢弃帧统计信息 Log Level = 日志等级 Log View = 日志视图 -Logging Channels = 日志源 +Logging Channels = 记录日志分类 Next = 下一个 No block = 没有内存块 Prev = 之前 @@ -262,7 +258,6 @@ RestoreDefaultSettings = 您确定要将所有设置恢复到默认? (按键映 RestoreGameDefaultSettings = 您确定要将此游戏设置\n恢复为PPSSPP默认吗? Resume = 恢复 Run CPU Tests = 运行CPU测试 -Save language ini = 保存语言配置 Save new textures = 保存新纹理 Shader Viewer = 着色器查看器 Show Developer Menu = 显示开发者菜单 @@ -284,7 +279,7 @@ Cancel = 取消 Center = 中心 ChangingGPUBackends = 更改引擎模式后需要重启PPSSPP。立刻重启? ChangingInflightFrames = 更改缓冲图形命令后需要重启PPSSPP。立刻重启? -Channel: = 频道: +Channel: = 信道: Choose PPSSPP save folder = 选择PPSSPP存档的文件夹 Confirm Overwrite = 您要覆盖这个存档吗? Confirm Save = 您要保存到这个存档吗? @@ -318,6 +313,8 @@ Load completed = 已载入。 Loading = 载入中\n请稍候... LoadingFailed = 无法载入存档。 Move = 移动 +Move Down = Move Down +Move Up = Move Up Network Connection = 网络连接 NEW DATA = 新建存档 No = 否 @@ -325,6 +322,7 @@ ObtainingIP = 获取IP地址.\n请稍候... OK = 确定 Old savedata detected = 检测到旧版本的存档数据 Options = 选项 +Remove = Remove Reset = 重置 Resize = 调整大小 Retry = 重试 @@ -460,6 +458,8 @@ Aggressive = 激进 Alternative Speed = 自定义速度 Alternative Speed 2 = 自定义速度2 Anisotropic Filtering = 各向异性过滤 +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = 宽高比 Auto = 自动 Auto (1:1) = 自动(1:1) Auto (same as Rendering) = 自动(同渲染分辨率) @@ -469,11 +469,8 @@ Auto Scaling = 自动缩放 Backend = 渲染引擎 Balanced = 均衡 Bicubic = 双三次 -BlockTransfer Tip = 有些游戏需要将此选项设置为开以显示正确的图形 -BlockTransferRequired = 警告:此游戏需要将"模拟块传输模式"设置为开。 Both = 全部显示 -Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 有输入延迟) -Buffered Rendering = 缓冲渲染 +Buffer graphics commands (faster, input lag) = 缓冲图形命令(更快, 增加输入延迟) BufferedRenderingRequired = 警告:此游戏需要将"渲染模式"设置为"缓冲渲染"。 Camera = 摄像头 Camera Device = 摄像头设备 @@ -491,16 +488,16 @@ Device = 设备 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = 禁用 -Display layout editor = 显示布局编辑器 -Display Resolution (HW scaler) = 显示分辨率(硬件缩放) -Dump next frame to log = 转储下一帧到日志 +Display Layout && Effects = 屏幕布局/滤镜 +Display Resolution (HW scaler) = 屏幕分辨率 Enable Cardboard VR = 启用Cardboard VR FPS = 每秒帧数 (FPS) Frame Rate Control = 帧率控制 Frame Skipping = 跳帧 Frame Skipping Type = 跳帧方式 FullScreen = 全屏幕 -GPU log profiler = GPU日志分析器 +Geometry shader culling = Geometry shader culling +GPUReadbackRequired = 警告: 此游戏需要"跳过GPU回读"设置为关闭 Hack Settings = 渲染修正(可能引发故障) Hardware Tessellation = 硬件曲面细分 Hardware Transform = 硬件几何变换 @@ -517,7 +514,7 @@ Linear = 线性过滤 Low = 低 LowCurves = 低品质样条函数/贝塞尔曲线(提速) LowCurves Tip = 仅对部分游戏有效, 控制曲线的平滑度 -Lower resolution for effects (reduces artifacts) = 降低特效分辨率(减少失真) +Lower resolution for effects (reduces artifacts) = 降低特效分辨率(减少图像错误) Manual Scaling = 手动缩放 Medium = 中 Mode = 渲染模式 @@ -525,7 +522,7 @@ Must Restart = 重启PPSSPP才能使这项设置生效。 Native device resolution = 本机原生的分辨率 Nearest = 邻近取样 No buffer = 不缓冲 -Non-Buffered Rendering = 跳过缓冲(更快) +Skip Buffer Effects = 跳过缓冲效果(不缓冲, 更快) None = 不显示 Number of Frames = 帧的数量 Off = 关闭 @@ -534,29 +531,28 @@ Overlay Information = 叠加信息 Partial Stretch = 部分拉伸 Percent of FPS = 帧率的百分比 Performance = 性能 -Postprocessing effect = 后处理效果 -Postprocessing Shader = 后处理着色器 +Postprocessing shaders = 后处理着色器 Recreate Activity = 重建进程 Render duplicate frames to 60hz = 渲染重复帧至60Hz RenderDuplicateFrames Tip = 在较低帧率的游戏中可以使帧速率更平滑 Rendering Mode = 渲染模式 Rendering Resolution = 渲染分辨率 RenderingMode NonBuffered Tip = 更快,但可能在某些游戏中丢失特效 -Retain changed textures = 保留已更改的纹理(有时更慢) -RetainChangedTextures Tip = 使较多游戏减速, 但有些游戏可能变快很多 -Rotation = 旋转 +Rotation = 方向 Safe = 安全 -Screen layout = 屏幕布局 -Screen Scaling Filter = 屏幕缩放滤镜 +Screen Scaling Filter = 缩放方法 Show Debug Statistics = 显示调试信息 Show FPS Counter = 显示FPS计数器 -Simulate Block Transfer = 模拟数据块传输效果 +Skip GPU Readbacks = 跳过GPU回读 Software Rendering = 软件渲染(慢) Software Skinning = 软件蒙皮 SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快 Speed = 运行速度 -Stretching = 拉伸 -Texture Filter = 纹理过滤方式 +Speed Hacks = 提速修正 (引起不稳定性) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = 拉伸 +Texture Filter = 纹理过滤方法 Texture Filtering = 纹理过滤 Texture Scaling = 纹理缩放 Texture Shader = 纹理着色器 @@ -565,7 +561,7 @@ Unlimited = 无限制 Up to 1 = 最高为1 Up to 2 = 最高为2 Upscale Level = 纹理缩放级别 -Upscale Type = 纹理缩放方式 +Upscale Type = 纹理缩放方法 UpscaleLevel Tip = CPU重负载-为避免卡顿, 某些缩放可能会延迟 Use all displays = 使用全部显示器 Vertex Cache = 顶点缓存 @@ -724,7 +720,7 @@ DataCannotBeShared = 数据无法在普通版/黄金版之间共用! DataWillBeLostOnUninstall = 警告!卸载PPSSPP将丢失全部数据! DataWillStay = 卸载PPSSPP时会保留数据。 Done! = 完成! -EasyUSBAccess = 轻松USB访问 +EasyUSBAccess = USB连接更简单 Failed to move some files! = 无法移动部分文件! Failed to save config = 无法保存配置! Free space = 可用空间 @@ -755,7 +751,7 @@ Bottom Right = 右下方 Center Left = 左中间 Center Right = 右中间 Change Mac Address = 更改MAC地址 -Change proAdhocServer Address = 更改PRO Ad Hoc服务器IP地址(localhost=模拟器双开) +Change proAdhocServer Address = 更改PRO Ad Hoc服务器IP地址(localhost=多个实例) ChangeMacSaveConfirm = 生成新的MAC地址? ChangeMacSaveWarning = 一些游戏会在载入存档数据时验证MAC地址,这可能会破坏旧的存档。 Chat = 聊天 @@ -809,7 +805,7 @@ UPnP (port-forwarding) = UPnP(端口转发) UPnP need to be reinitialized = UPnP 需要重新初始化 UPnP use original port = UPnP 使用原始端口(启用=兼容PSP) Validating address... = 正在验证地址... -WLAN Channel = WLAN 频道 +WLAN Channel = WLAN信道 You're in Offline Mode, go to lobby or online hall = 您现在是离线模式, 请进入房间或在线大厅 [Pause] @@ -829,9 +825,9 @@ Undo last save = 撤销保存 [PostShaders] (duplicated setting, previous slider will be used) = (设置重复, 将使用上面滑块的值) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = 数量 Animation speed (0 -> disable) = 动画速度(0->禁用) @@ -840,21 +836,24 @@ Bloom = 泛光 Brightness = 亮度 Cartoon = 卡通 ColorCorrection = 颜色修正 +ColorPreservation = Color preservation Contrast = 对比度 CRT = CRT 扫描线 FXAA = FXAA (快速近似抗锯齿) Gamma = 伽马值 -Grayscale = 灰度图 +GreenLevel = Green level Intensity = 强度 -InverseColors = 反色 +LCDPersistence = LCD Persistence Natural = 自然色 NaturalA = 自然色(无模糊) Off = 关闭 Power = 效果强度 PSPColor = PSP色彩 +RedBlue = Red/Blue glasses Saturation = 色彩 Scanlines = 扫描线(CRT) Sharpen = 锐化 +SideBySide = Side by side (SBS) SSAA(Gauss) = 超级采样抗锯齿(高斯) Tex4xBRZ = 4xBRZ TexMMPX = MMPX @@ -1019,8 +1018,10 @@ Size = 大小 Uninstall = 卸载 [SysInfo] +%0.2f Hz = %0.2f Hz %d (%d per core, %d cores) = %d (每核心%d线程, %d核心) %d bytes = %d字节 +%d Hz = %d Hz (none detected) = (未检测到) 3D API = 3D API ABI = ABI @@ -1038,6 +1039,7 @@ CPU Name = CPU 名称 D3DCompiler Version = D3DCompiler版本 Debug = 调试 Debugger Present = 调试器已连接 +Depth buffer format = Depth buffer format Device Info = 设备信息 Directories = 路径 Display Color Formats = 显示颜色格式 @@ -1093,6 +1095,8 @@ Color Saturation = 颜色饱和度 Error: load undo state is from a different game = 错误:撤回的即时存档是来自不同游戏的 Failed to load state for load undo. Error in the file system. = 无法撤回加载即时存档。文件系统有错误。 Floating symbols = 飘浮的按键 +Game crashed = Game crashed +Language = 语言设置 Memory Stick folder = 记忆棒文件夹 Memory Stick size = 记忆棒大小(GB) Change Nickname = 修改昵称 @@ -1130,7 +1134,7 @@ Host (bugs, less lag) = 主机(较少延迟,有错误) Ignore bad memory accesses = 忽略错误的内存访问 Increase size = 增大尺寸 Interpreter = 解释器 -IO timing method = I/O计时方法 +IO timing method = I/O 计时方法 IR Interpreter = IR解释器 Memory Stick Folder = 记忆棒文件夹 Memory Stick inserted = 记忆棒已插入 @@ -1139,7 +1143,7 @@ MMDDYYYY = 月/日/年 Moving background = 动态壁纸 Newest Save = 最新的即时存档 No animation = 静态壁纸 -Not a PSP game = 这不是一个PSP游戏 +Not a PSP game = 这不是一个 PSP 游戏 Off = 关闭 Oldest Save = 最旧的即时存档 Path does not exist! = 路径不存在! @@ -1152,7 +1156,7 @@ Recent games = 最近的游戏 Record Audio = 录制音频 Record Display = 录制视频 Reset Recording on Save/Load State = 保存/载入存档时重置录制 -Restore Default Settings = 恢复默认PPSSPP设置 +Restore Default Settings = 恢复默认 PPSSPP 设置 Rewind Snapshot Frequency = 倒带自动即时存档频率 Save path in installed.txt = 存档路径在installed.txt Save path in My Documents = 存档路径在我的文档 @@ -1162,7 +1166,7 @@ Screenshots as PNG = 将截图保存为PNG格式 Set UI background... = 设置界面背景... Show ID = 显示游戏ID Show region flag = 显示游戏区域标识 -Simulate UMD delays = 模拟UMD延迟 +Simulate UMD delays = 模拟 UMD 延迟 Slot 1 = 插槽1 Slot 2 = 插槽2 Slot 3 = 插槽3 @@ -1176,7 +1180,7 @@ UI background animation = 界面背景效果 UI Sound = 界面声音 undo %c = 备份 %c USB = USB -Use Lossless Video Codec (FFV1) = 使用无损视频编解码器(FFV1) +Use Lossless Video Codec (FFV1) = 使用无损视频编解码器 (FFV1) Use O to confirm = 使用按钮O确认 Use output buffer (with overlay) for recording = 录制时使用输出缓冲(包括叠加信息) Use system native keyboard = 使用系统本机键盘 @@ -1214,7 +1218,7 @@ Screen representation = 屏幕表现 Details = 详细内容 Dismiss = 忽略 Download = 下载 -New version of PPSSPP available = 新版本PPSSPP可用 +New version of PPSSPP available = 新版本 PPSSPP 可用 [Search] Filtering settings by '%1' = 设置筛选'%1' @@ -1222,3 +1226,17 @@ Find settings = 搜索设置 Filter = 筛选 Clear filter = 清除筛选结果 No settings matched '%1' = 未找到设置'%1' + +[VR] +% of native FoV = % of 原生 FoV +6DoF movement = 6自由度移动 +Distance to 2D menus and scenes = 2D 菜单和场景的距离 +Field of view scale = 视野比例 +Force 72Hz update = 强制72赫兹更新 +Heads-up display scale = 平视显示比例 +Map controller movements to keys = 映射控制器移动到关键点 +Motion needed to generate action = 运动捕捉所需的行动 +Stereoscopic vision (Experimental) = 立体视觉(试验性) +Virtual reality = 虚拟现实 +VR camera = VR 摄像 +VR controllers = VR 控制器 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 3559284b19..7d2388c25a 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1,1207 +1,1199 @@ [Audio] -Alternate speed volume = 自定義速度下的音量 -Audio backend = 音訊引擎(需要重新啟動) +Alternate speed volume = 替代速度音量 +Audio backend = 音訊後端 (需要重新啟動) Audio Error = 音訊錯誤 -AudioBufferingForBluetooth = 藍牙友好緩衝區(較慢) +AudioBufferingForBluetooth = 藍牙友好緩衝區 (更慢) Auto = 自動 -Device = 設備 -Disabled = Disabled -DSound (compatible) = DirectSound(兼容) +Device = 裝置 +Disabled = 已停用 +DSound (compatible) = DSound (相容) Enable Sound = 啟用音效 -Global volume = 全局音量 -Microphone = Microphone +Global volume = 全域音量 +Microphone = 麥克風 Microphone Device = 麥克風裝置 Mute = 靜音 -Reverb volume = 混響音量 -Use new audio devices automatically = 自動開啟新的音頻設備 -Use global volume = 使用全局量 -WASAPI (fast) = WASAPI(快) +Reverb volume = 混響裝置音量 +Use new audio devices automatically = 自動使用新音訊裝置 +Use global volume = 使用全域音量 +WASAPI (fast) = WASAPI (快) [Controls] -Analog Binding = 搖桿綁定 -Analog Settings = 搖桿配置 -Analog Style = 搖桿樣式 -Auto-rotation speed = 模擬自動轉速 -Analog Limiter = 搖桿限制器 +Analog Binding = 類比繫結 +Analog Limiter = 類比限制器 +Analog Settings = 類比設定 Analog Stick = 類比搖桿 -AnalogLimiter Tip = 按下模擬限制器按鈕時 +Analog Style = 類比樣式 +AnalogLimiter Tip = 類比限制器按鈕被按下時 Auto = 自動 -Auto-centering analog stick = 自動定心搖桿 +Auto-centering analog stick = 自動置中類比搖桿 Auto-hide buttons after seconds = 數秒後自動隱藏按鈕 -Auto-switch = 自動轉換 -Base tilt position = 標準體感位置 -Binds = 綁定 -Button Binding = 按鈕綁定 -Button Opacity = 按鈕透明度 +Auto-rotation speed = 自動旋轉速度 +Auto-switch = 自動切換 +Base tilt position = 基準傾斜位置 +Binds = 繫結 +Button Binding = 按鈕繫結 +Button Opacity = 按鈕不透明度 Button style = 按鈕樣式 -Calibrate Analog Stick = 校準搖桿 -Calibrate D-Pad = 校正方向鍵 -Calibrated = 校正後 +Calibrate Analog Stick = 校正類比搖桿 +Calibrate D-Pad = 校正 +Calibrated = 已校正 Calibration = 校正 -Circular stick input = 環形搖桿錄入 +Circular stick input = 圓形搖桿輸入 Classic = 傳統 -Confine Mouse = 在窗口/顯示區域內捕獲鼠標 -Control Mapping = 按鍵對應 -Custom Key Setting = 自訂鍵位配置 +Confine Mouse = 在視窗/顯示區域內截獲滑鼠 +Control Mapping = 控制對應 +Custom Key Setting = 自訂按鍵設定 Customize = 自訂 -Customize Touch Controls = 自訂佈局 -Customize tilt = 自訂傾斜 +Customize Touch Controls = 編輯觸控控制版面配置… +Customize tilt = 自訂傾斜… D-PAD = 方向鍵 Deadzone radius = 死區半徑 -Disable D-Pad diagonals (4-way touch) = 停用方向鍵對角線(四方向觸控) -Disable diagonal input = 停用對角線錄入 -Double tap = 雙擊 -Enable gesture control = 開啓體感控制 -Enable standard shortcut keys = 開啓標準熱鍵 -Gesture = 體感 -Gesture mapping = 體感映射 -Glowing borders = 細邊框 -HapticFeedback = 按鍵反饋(震動) -Hide touch analog stick background circle = 隱藏觸屏搖桿背景圈 -Icon = 圖標 -Ignore gamepads when not focused = 非作用時忽略遊戲手把 -Ignore Windows Key = 忽略Windows鍵 -Invert Axes = 軸反轉 -Invert Tilt along X axis = 沿X軸傾斜反轉 -Invert Tilt along Y axis = 沿Y軸傾斜反轉 -Keep this button pressed when right analog is pressed = 點擊右模擬鍵時保持點擊此按鈕 +Disable D-Pad diagonals (4-way touch) = 停用方向鍵對角線 (四向觸控) +Disable diagonal input = 停用對角線輸入 +Double tap = 點兩下 +Enable gesture control = 啟用手勢控制 +Enable standard shortcut keys = 啟用標準快速鍵 +Gesture = 手勢 +Gesture mapping = 手勢對應 +Glowing borders = 發光框線 +HapticFeedback = 觸覺回饋 (震動) +Hide touch analog stick background circle = 隱藏觸控式類比搖桿背景圓環 +Icon = 圖示 +Ignore gamepads when not focused = 未聚焦時忽略手把 +Ignore Windows Key = 停用 Windows 按鍵 +Invert Axes = 反轉軸 +Invert Tilt along X axis = 沿 X 軸反轉傾斜 +Invert Tilt along Y axis = 沿 Y 軸反轉傾斜 +Keep this button pressed when right analog is pressed = 右類比搖桿被按下時保持此按鈕按下 Keyboard = 鍵盤控制設定 -L/R Trigger Buttons = L/R觸發按鈕 -#L/R扳机按钮 +L/R Trigger Buttons = L/R 觸發按鈕 Landscape = 橫向 -Landscape Auto = 自動橫向 +Landscape Auto = 橫向自動 Landscape Reversed = 橫向反轉 -Low end radius = 尾端半徑 -Mouse = 鼠標配置 -Mouse sensitivity = 鼠標靈敏度 -Mouse smoothing = 鼠標平滑 -MouseControl Tip = 您現在可以在按鍵映射界面上按“ M”圖標來映射鼠標按鍵。 -None (Disabled) = 無(停用) +Low end radius = 低端半徑 +Mouse = 滑鼠設定 +Mouse sensitivity = 滑鼠敏感度 +Mouse smoothing = 滑鼠平滑度 +MouseControl Tip = 您現在可以透過按下「M」圖示在控制對應畫面中對應滑鼠。 +None (Disabled) = 無 (已停用) Off = 關閉 -OnScreen = 顯示虛擬控制器 -Portrait = 縱向 -Portrait Reversed = 縱向反轉 -PSP Action Buttons = PSP功能鍵 -Raw input = 原始錄入 -Repeat mode = Repeat mode -#重复模式 -Reset to defaults = 重置爲默認 -Screen aligned to ground = 屏幕水平地面 -Screen at right angle to ground = 屏幕垂直地面 +OnScreen = 螢幕觸控控制 +Portrait = 直向 +Portrait Reversed = 直向反轉 +PSP Action Buttons = PSP 動作按鈕 +Raw input = 原始輸入 +Reset to defaults = 重設為預設值 +Screen aligned to ground = 螢幕與地面水平對齊 +Screen at right angle to ground = 螢幕與地面垂直對齊 Screen Rotation = 螢幕旋轉 seconds, 0 : off = 秒,0 = 關閉 -Sensitivity (scale) = 靈敏度(倍數) -Sensitivity = 靈敏度 -Shape = 形狀 -Show Touch Pause Menu Button = 顯示觸控暫停選單鍵 +Sensitivity = 敏感度 +Sensitivity (scale) = 敏感度 (比例) +Shape = 圖形 +Show Touch Pause Menu Button = 顯示暫停選單按鈕 Swipe = 滑動 -Swipe sensitivity = 滑動靈敏性 -Swipe smoothing = 滑動光滑度 -Thin borders = 薄邊框 -Tilt Base Radius = 傾斜基本半徑 +Swipe sensitivity = 滑動敏感度 +Swipe smoothing = 滑動平滑度 +Thin borders = 特細框線 +Tilt Base Radius = 傾斜基準半徑 Tilt Input Type = 傾斜輸入類型 -Tilt Sensitivity along X axis = 沿X軸傾斜靈敏度 -Tilt Sensitivity along Y axis = 沿Y軸傾斜靈敏度 -To Calibrate = 請將裝置放在平面上,然後按「校正」。 +Tilt Sensitivity along X axis = 沿 X 軸傾斜敏感度 +Tilt Sensitivity along Y axis = 沿 Y 軸傾斜敏感度 +To Calibrate = 若要校正,把裝置放置水平表面,然後按下「校正」。 Toggle mode = 切換模式 -Touch Control Visibility = 觸控可視性 -Use custom right analog = 使用自定義右模擬 -Use Mouse Control = 使用鼠標控制 -Visibility = 可視設定 -Visible = 可視 +Repeat mode = 重複模式 +Touch Control Visibility = 觸控控制可見性 +Use custom right analog = 使用自訂右類比搖桿 +Use Mouse Control = 使用滑鼠控制 +Visibility = 可見性 +Visible = 可見 X = X Y = Y [CwCheats] -Cheats = 金手指 -Edit Cheat File = 編輯金手指文件 -Enable/Disable All = 全部啟用/停用 -Import Cheats = 由cheat.db匯入 +Cheats = 密技 +Edit Cheat File = 編輯密技檔案 +Enable/Disable All = 啟用/停用所有密技 +Import Cheats = 從 cheat.db 匯入 Options = 選項 -Refresh Rate = 刷新率 +Refresh Rate = 重新整理速率 [DesktopUI] # If your language does not show well with the default font, you can use Font to specify a different one. # Just add it to your language's ini file and uncomment it (remove the # by Font). -Auto Max Quality = 自動最高質量 (&Q) Font = Microsoft JhengHei -About PPSSPP... = 關於PPSSPP (&A)... -Auto = 自動 (&A) -Backend = 繪圖引擎(需要重新啟動) (&b) -Bicubic = 雙立方 (&B) -Break = 停止 -Break on Load = 載入后停止 -Buffered Rendering = 緩衝渲染 (&B) -Buy Gold = 購買黃金版 (&G) -Control Mapping... = 按鍵對應 (&O)... -Debugging = 除錯 (&D) -Deposterize = 色調混合 (&D) -Direct3D9 = Direct3D 9 (&9) -Direct3D11 = Direct3D 11 (&11) -Disassembly = 反組譯 (&D) +About PPSSPP... = 關於 PPSSPP(&A)… +Auto = 自動(&A) +Auto Max Quality = 自動最高品質(&Q) +Backend = 轉譯後端 (需要重新啟動)(&B) +Bicubic = 雙立方(&B) +Break = 中斷 +Break on Load = 載入時中斷 +Buy Gold = 購買黃金版(&G) +Control Mapping... = 控制對應(&O)… +Debugging = 偵錯(&D) +Deposterize = 色調混合(&D) +Direct3D9 = Direct3D 9(&9) +Direct3D11 = Direct3D 11(&11) +Disassembly = 反組譯碼(&D)… Discord = Discord -Display Layout Editor = 自訂版面 -Display Rotation = 旋轉畫面 -Dump Next Frame to Log = 轉儲下一幀到除錯日誌 -Emulation = 模擬 (&E) -Enable Cheats = 啓用金手指 (&C) -Enable Sound = 開啟聲音 (&O) -Exit = 離開 (&X) -Extract File... = 提取檔案 (&F)... -File = 檔案 (&F) -Frame Skipping = 跳幀 (&F) -Frame Skipping Type = 跳幀類型 -Fullscreen = 全螢幕 (&L) -Game Settings = 遊戲設定 (&G) -GE Debugger... = GE 除錯器 (&R) +Display Layout && Effects = 顯示版面配置與效果… +Display Rotation = 顯示旋轉 +Dump Next Frame to Log = 傾印下一影格至記錄(&U) +Emulation = 模擬(&E) +Enable Cheats = 啟用密技(&C) +Enable Sound = 啟用音效(&O) +Exit = 離開(&X) +Extract File... = 擷取檔案(&X)… +File = 檔案(&F) +Frame Skipping = 影格跳過(&F) +Frame Skipping Type = 影格跳過類型 +Fullscreen = 全螢幕(&L) +Game Settings = 遊戲設定(&G) +GE Debugger... = GE 偵錯工具(&R)… GitHub = Git&Hub -Hardware Transform = 硬體幾何轉換 (&H) -Help = 幫助 (&H) -Hybrid = 混合 (&H) -Hybrid + Bicubic = 混合+雙立方 (&Y) -Ignore Illegal Reads/Writes = 忽略非法存取 (&I) -Ignore Windows Key = 忽略Windows鍵 -Keep PPSSPP On Top = 保持PPSSPP視窗在最上層 (&K) -Landscape = 横向 +Hardware Transform = 硬體轉換(&H) +Help = 說明(&H) +Hybrid = 混合(&H) +Hybrid + Bicubic = 混合 + 雙立方(&Y) +Ignore Illegal Reads/Writes = 忽略非法存取(&I) +Ignore Windows Key = 忽略 Windows 按鍵 +Keep PPSSPP On Top = 保持 PPSSPP 視窗在最上層(&K) +Landscape = 橫向 Landscape reversed = 橫向反轉 -Language... = 語言設定 (&a) -Linear = 線性 (&L) -Load = 載入遊戲 (&L) -Load .sym File... = 載入.sym檔案 (&A)... -Load Map File... = 載入Map檔案(&M)... -Load State = 載入即時存檔 (&O) -Load State File... = 載入即時存檔檔案 (&L)... -Log Console = 控制台日誌 (&L) -Memory View... = 查看記憶體 (&M)... -More Settings... = 更多設定 (&M) -Nearest = 臨近取樣 (&N) -Non-Buffered Rendering = 跳過緩衝效果 (不緩衝,速度更快) (&S) -Off = 關閉 (&O) -Open Chat = 打開聊天 -Open Directory... = 打開目錄 (&D)... -Open from MS:/PSP/GAME... = 打開 MS:/PSP/GAME (&P)... -#从MS:/PSP/GAME处打开 (&p)... -Open Memory Stick = 打開記憶卡 (&M) -Open New Instance = 打開新實例 -OpenGL = OpenGL (&O) -Pause = 暫停 (&P) -Pause When Not Focused = 非使用中時暫停 (&P) -Portrait = 縱向 -Portrait reversed = 縱向反轉 -Postprocessing Shader = 後處理著色器 (&G) -PPSSPP Forums = PPSSPP 官方論壇 (&F) -Record = 錄製 (&R) -Record Audio = 錄音 (&A) -Record Display = 錄製畫面 (&D) -Rendering Mode = 渲染模式 (&O) -Rendering Resolution = 渲染解析度 (&R) -Reset = 重置 (&E) -Reset Symbol Table = 重置符號表 (&R) -Run = 執行 (&R) -Save .sym File... = 保存.sym檔案 (&e)... -Save Map File... = 保存Map檔案 (&S)... -Save State = 即時存檔 (&a) -Save State File... = 保存即時存檔檔案 (&S)... -Savestate Slot = 即時存檔插槽 (&t) -Screen Scaling Filter = 螢幕縮放濾鏡 (&e) -Show Debug Statistics = 顯示除錯數據 (&g) -Show FPS Counter = 顯示FPS計數器 (&F) -Skip Number of Frames = 跳過幀數 -Skip Percent of FPS = 跳過FPS的百分比 -Stop = 停止 (&S) -Switch UMD = 切換UMD光碟 -Take Screenshot = 截圖 (&T) -Texture Filtering = 紋理過濾 (&x) -Texture Scaling = 紋理縮放 (&T) -Use Lossless Video Codec (FFV1) = 使用無損視訊轉碼器(FFV1) (&U) -Use output buffer for video = 將輸出緩衝區用於視頻 -Vertex Cache = 頂點快取 (&V) -VSync = 垂直同步 (&y) +Language... = 語言(&N)… +Linear = 線性(&L) +Load = 載入(&L)… +Load .sym File... = 載入 .sym 檔案(&A)… +Load Map File... = 載入對應檔案(&M)… +Load State = 載入存檔(&O) +Load State File... = 載入存檔檔案(&L)… +Log Console = 記錄主控台(&L) +Memory View... = 記憶體檢視(&V)… +More Settings... = 更多設定(&M)… +Nearest = 鄰近取樣(&N) +Skip Buffer Effects = 跳過緩衝區效果(&S) +Off = 關閉(&O) +Open Chat = 開啟聊天 +Open Directory... = 開啟目錄(&D)… +Open from MS:/PSP/GAME... = 開啟自 MS:/PSP/GAME(&P)… +Open Memory Stick = 開啟記憶棒(&M) +Open New Instance = 開啟新執行個體 +OpenGL = OpenGL(&O) +Pause = 暫停(&P) +Pause When Not Focused = 未聚焦時暫停(&P) +Portrait = 直向 +Portrait reversed = 直向反轉 +PPSSPP Forums = PPSSPP 論壇(&F) +Record = 錄製(&R) +Record Audio = 錄製音訊(&A) +Record Display = 錄製視訊(&D) +Rendering Mode = 轉譯模式(&O) +Rendering Resolution = 轉譯解析度(&R) +Reset = 重設(&E) +Reset Symbol Table = 重設符號表(&Y) +Run = 執行(&R) +Save .sym File... = 儲存 .sym 檔案(&E)… +Save Map File... = 儲存對應檔案(&S)… +Save State = 儲存存檔(&A) +Save State File... = 儲存存檔檔案(&S)… +Savestate Slot = 存檔插槽(&T) +Screen Scaling Filter = 螢幕縮放濾鏡(&E) +Show Debug Statistics = 顯示偵錯統計資料(&G) +Show FPS Counter = 顯示 FPS 計數器(&F) +Skip Number of Frames = 跳過影格數 +Skip Percent of FPS = 跳過 FPS 百分比 +Stop = 停止(&S) +Switch UMD = 切換 UMD +Take Screenshot = 擷取螢幕畫面(&T) +Texture Filtering = 紋理過濾(&X) +Texture Scaling = 紋理縮放(&T) +Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1)(&U) +Use output buffer for video = 為視訊使用輸出緩衝區 +Vertex Cache = 頂點快取(&V) +VSync = 垂直同步(&Y) Vulkan = Vulkan -Window Size = 視窗大小 (&W) -www.ppsspp.org = 拜訪www.&ppsspp.org +Window Size = 視窗大小(&W) +www.ppsspp.org = 造訪 www.&ppsspp.org xBRZ = &xBRZ [Developer] -Allocator Viewer = 分配器查看器(Vulkan) -Allow remote debugger = 允許遠程調試器 -Backspace = 向前刪除 +Allocator Viewer = 配置器檢視器 (Vulkan) +Allow remote debugger = 允許遠端偵錯工具 +Backspace = 退格鍵 Block address = 區塊位址 -By Address = 由位址 -Copy savestates to memstick root = 副本保存狀態,以記憶棒根目錄 -Create/Open textures.ini file for current game = 創建/打開當前游戲的textures.ini文件 +By Address = 依位址 +Copy savestates to memstick root = 複製存檔至記憶棒根目錄 +Create/Open textures.ini file for current game = 為目前遊戲建立/開啟 textures.ini 檔案 Current = 目前 Dev Tools = 開發工具 -DevMenu = 開發菜單 -Disabled JIT functionality = 禁用JIT功能 -Draw Frametimes Graph = 繪製幀時間圖 -Dump Decrypted Eboot = 載入遊戲時,轉儲已解密的EBOOT.BIN -Dump Frame GPU Commands = 轉儲幀GPU指令 -Enable driver bug workarounds = 啟用驅動程序錯誤解決方法 -Enable Logging = 啟用日誌 +DevMenu = 開發選單 +Disabled JIT functionality = 停用 JIT 功能 +Draw Frametimes Graph = 繪製影格時間圖形 +Dump Decrypted Eboot = 遊戲啟動時傾印已解密的 EBOOT.BIN +Dump next frame to log = 將下一個影格傾印至記錄 +Enable driver bug workarounds = 啟用驅動程式錯誤因應措施 +Enable Logging = 啟用偵錯記錄 Enter address = 輸入位址 FPU = FPU -Framedump tests = 幀轉儲測試 -Frame Profiler = 幀分析器 -GPU Driver Test = GPU驅動程序測試 -GPU Log Profiler = GPU日志分析器 -GPU Profile = GPU配置文件 -Jit Compare = Jit比較 -JIT debug tools = JIT調試工具 -Language = 語言設定 -Load language ini = 載入語言設定 -Log Dropped Frame Statistics = 日志丟棄幀統計信息 -Log Level = 日誌級別 -Log View = 查看日誌 -Logging Channels = 記錄頻道 +Framedump tests = 影格傾印測試 +Frame Profiler = 影格分析工具 +GPU Driver Test = GPU 驅動程式測試 +GPU Profile = GPU 設定檔 +GPU log profiler = GPU 記錄分析工具 +Jit Compare = JIT 比較 +JIT debug tools = JIT 偵錯工具 +Log Dropped Frame Statistics = 記錄捨棄影格統計資料 +Log Level = 記錄層級 +Log View = 記錄檢視 +Logging Channels = 記錄通道 Next = 下一個 -No block = 沒有記憶體區塊 +No block = 沒有區塊 Prev = 上一個 Random = 隨機 -Replace textures = 紋理更換 -Reset = 重置 -Reset limited logging = 重置受限日誌 -RestoreDefaultSettings = 你確定要所有設定還原到預設值 (除了按鍵配置)?\n此動作無法恢復。\n需要重新啟動PPSSPP,變更才會生效。 -RestoreGameDefaultSettings = 你確定要恢復特定遊戲的配置,\n回到PPSSPP的預設值? +Replace textures = 取代紋理 +Reset = 重設 +Reset limited logging = 重設受限記錄 +RestoreDefaultSettings = 您確定要將所有設定還原為預設值嗎?\n控制對應設定將不會變更。\n\n您無法復原此動作。\n請重新啟動 PPSSPP 以使變更生效。 +RestoreGameDefaultSettings = 您確定要將遊戲特定設定\n還原為 PPSSPP 預設值嗎? Resume = 恢復 -Run CPU Tests = 執行CPU測試 -Save language ini = 儲存語言設定 -Save new textures = 保存新纹理 -Shader Viewer = 著色器查看器 -Show Developer Menu = 顯示開發者選單 -Show on-screen messages = 顯示屏幕消息 -Stats = 統計 -System Information = 系統資料 -Texture ini file created = 創建紋理INI文件 -Texture Replacement = 纹理更换 -Toggle Audio Debug = 切換音訊除錯 -Toggle Freeze = 切換凍結 -Touchscreen Test = 觸摸屏測試 +Run CPU Tests = 執行 CPU 測試 +Save new textures = 儲存新紋理 +Shader Viewer = 著色器檢視器 +Show Developer Menu = 顯示開發人員選單 +Show on-screen messages = 顯示螢幕訊息 +Stats = 統計資料 +System Information = 系統資訊 +Texture ini file created = 紋理 ini 檔案已建立 +Texture Replacement = 紋理取代 +Toggle Audio Debug = 切換音訊偵錯開關 +Toggle Freeze = 切換凍結開關 +Touchscreen Test = 觸控式螢幕測試 VFPU = VFPU [Dialog] -* PSP res = * PSP解析度 -Active = 激活 +* PSP res = * PSP 解析度 +Active = 啟用 Back = 返回 Cancel = 取消 -Center = 中間 -ChangingGPUBackends = 改變渲染引擎之後需要重新啟動PPSSPP。現在重新啟動嗎? -ChangingInflightFrames = 更改圖形命令緩衝要求PPSSPP重新啟動。 現在重啟? -Channel: = 頻道: -Choose PPSSPP save folder = 選擇PPSSPP的存檔資料夾 -Confirm Overwrite = 你要覆蓋這份檔案嗎? -Confirm Save = 你要儲存這份檔案嗎? -ConfirmLoad = 你要載入這份檔案嗎? -ConnectingAP = 連接到接入點\n請稍候... -ConnectingPleaseWait = 連接中.\n請稍候... -ConnectionName = 連接名稱 -Corrupted Data = 數據損壞 +Center = 中心 +ChangingGPUBackends = 變更 GPU 後端需要重新啟動 PPSSPP,要立即重新啟動嗎? +ChangingInflightFrames = 變更圖形命令緩衝處理需要重新啟動 PPSSPP,要立即重新啟動嗎? +Channel: = 頻道: +Choose PPSSPP save folder = 選擇 PPSSPP 存檔資料夾 +Confirm Overwrite = 要覆寫這個存檔的資料嗎? +Confirm Save = 要儲存這個存檔的資料嗎? +ConfirmLoad = 要載入這個存檔的資料嗎? +ConnectingAP = 正在連線至存取點\n請稍候… +ConnectingPleaseWait = 正在連線\n請稍候… +ConnectionName = 連線名稱 +Corrupted Data = 已損毀的資料 Delete = 刪除 Delete all = 全部刪除 -Delete completed = 檔案已刪除。 -DeleteConfirm = 這份檔案將被刪除。\n你確定要繼續嗎? -DeleteConfirmAll = 你確定要刪除此遊戲的所有檔案? -DeleteConfirmGame = 你確定要刪除此遊戲?\n此動作無法還原。 -DeleteConfirmGameConfig = 你確定要刪除這個遊戲的配置? -DeleteFailed = 無法刪除資料。 -Deleting = 刪除中\n請稍候... -Disable All = 禁用所有 -Dumps = 轉儲 +Delete completed = 刪除完成 +DeleteConfirm = 這個存檔的資料將被刪除\n仍要繼續嗎? +DeleteConfirmAll = 您確定要刪除\n這個遊戲的全部存檔資料嗎? +DeleteConfirmGame = 您確定要從您的裝置上刪除這個遊戲嗎?\n您無法復原此動作。 +DeleteConfirmGameConfig = 您確定要刪除這個遊戲的全部設定嗎? +DeleteFailed = 無法刪除資料 +Deleting = 正在刪除\n請稍候… +Disable All = 全部停用 +Dumps = 傾印 Edit = 編輯 Enable All = 全部啟用 -Enter = 決定 -Filter = 篩選 +Enter = 輸入 +Filter = 篩選器 Finish = 完成 -GE Frame Dumps = GE幀轉儲 -Grid = 格 -Inactive = 不活躍 -InternalError = 發生了一個內部錯誤. +GE Frame Dumps = GE 影格傾印 +Grid = 格狀 +Inactive = 未啟用 +InternalError = 發生內部錯誤 Load = 載入 -Load completed = 檔案已載入。 -Loading = 載入中\n請稍候... -LoadingFailed = 無法載入資料。 -Move = 位置設定 +Load completed = 載入完成 +Loading = 正在載入\n請稍候… +LoadingFailed = 無法載入資料 +Move = 移動 +Move Down = 下移 +Move Up = 上移 Network Connection = 網路連線 -NEW DATA = 建立新檔案 +NEW DATA = 新存檔 No = 否 -ObtainingIP = 獲取IP地址.\n請稍候... +ObtainingIP = 正在取得 IP 位址\n請稍候… OK = 確定 -Old savedata detected = 偵測到舊版的存檔資料 +Old savedata detected = 偵測到舊版存檔資料 Options = 選項 +Remove = 移除 Reset = 重設 -Resize = 大小設定 -Retry = 重新嘗試 +Resize = 調整大小 +Retry = 重試 Save = 儲存 -Save completed = 檔案已儲存。 -Saving = 儲存中\n請稍候... -SavingFailed = 無法儲存資料。 +Save completed = 儲存完成 +Saving = 正在儲存\n請稍候… +SavingFailed = 無法儲存資料 Search = 搜尋 -Select = 選擇 -Shift = 翻頁 +Select = 選取 +Shift = 移位 Skip = 跳過 -Snap = 對齊 -Space = 空格鍵 +Snap = 貼齊 +Space = 空白 SSID = SSID Submit = 提交 -Supported = 支持 -There is no data = 沒有檔案。 +Supported = 支援 +There is no data = 沒有資料 Toggle All = 切換全部 -Toggle List = 切換列表 -Unsupported = 不支持 -When you save, it will load on a PSP, but not an older PPSSPP = 當您保存,它會加載一個真正的PSP,但不是舊版本PPSSPP -When you save, it will not work on outdated PSP Firmware anymore = 保存後,它將不再適用於過時的PSP固件 +Toggle List = 切換清單 +Unsupported = 不支援 +When you save, it will load on a PSP, but not an older PPSSPP = 在您儲存後,它將會只能在 PSP 上載入,而非舊版 PPSSPP +When you save, it will not work on outdated PSP Firmware anymore = 在您儲存後,它將無法在已過期的 PSP 韌體上運作 Yes = 是 -Zoom = 放大 +Zoom = 縮放 [Error] -7z file detected (Require 7-Zip) = 檔案是7z壓縮檔。\n請先解壓縮 (使用 7-zip 或 WinRAR)。 -A PSP game couldn't be found on the disc. = 光盤上找不到PSP遊戲. -Cannot boot ELF located outside mountRoot. = 無法引導位於裝載根外部的ELF. -Could not save screenshot file = 無法保存截圖檔案 -D3D9or11 = 使用 Direct3D 9? (或者 "否" 以使用Direct3D 11) -D3D11CompilerMissing = D3DCompiler_47.dll未找到。 請安裝。 或者按“是”,再次嘗試使用Direct3D 9。 -D3D11InitializationError = Direct3D 11初始化錯誤 -D3D11Missing = 您的操作系統版本不包括 D3D11。 請運行Windows Update.\n\n按是,嘗試使用 Direct3D 9. -D3D11NotSupported = 您的GPU似乎不支持Direct3D 11.\n\n您是否想改用Direct3D 9? -Disk full while writing data = 寫入數據時硬碟空間不足 -ELF file truncated - can't load = ELF文件被截斷-無法加載 -Error loading file = 檔案載入錯誤 -Error reading file = 讀取檔案錯誤 -Failed initializing CPU/Memory = 初始化CPU或內存失敗 -Failed to load executable: = 無法加載可執行文件: -File corrupt = 文件損壞 -Game disc read error - ISO corrupt = 遊戲光盤讀取錯誤:ISO損壞. -GenericAllStartupError = PPSSPP無法使用任何圖形後端啟動。 嘗試升級圖形和其他驅動程序. -GenericBackendSwitchCrash = 啟動時PPSSPP 崩潰了.\n\n這通常意味著圖形驅動程序問題。 嘗試升級圖形驅動程序.\n\n圖形後端已切換: -GenericDirect3D9Error = 圖形初始化失敗,請試著更新你的圖形驅動程式與DirectX 9 runtime。\n\n你要切換到 OpenGL 試試看嗎?\n\n錯誤訊息: +7z file detected (Require 7-Zip) = 檔案已壓縮 (7z)\n請先解壓縮 (嘗試 7-Zip 或 WinRAR) +A PSP game couldn't be found on the disc. = 此光碟上找不到 PSP 遊戲 +Cannot boot ELF located outside mountRoot. = 無法啟動位於 mountRoot 外的 ELF +Could not save screenshot file = 無法儲存螢幕截圖檔案 +D3D9or11 = 使用 Direct3D 9?(或「否」以使用 Direct3D 11) +D3D11CompilerMissing = 找不到 D3DCompiler_47.dll,請安裝或按下「是」以改為使用 Direct3D 9 +D3D11InitializationError = Direct3D 11 初始化錯誤 +D3D11Missing = 您的作業系統不包括 D3D11,請執行 Windows 更新\n\n按下「是」以改為使用 Direct3D 9 +D3D11NotSupported = 您的 GPU 似乎不支援 Direct3D 11\n\n要改為使用 Direct3D 9 並重試嗎? +Disk full while writing data = 寫入資料時磁碟已滿 +ELF file truncated - can't load = ELF 檔案已截斷 - 無法載入 +Error loading file = 無法載入遊戲 +Error reading file = 無法讀取檔案 +Failed initializing CPU/Memory = 無法初始化 CPU 或記憶體 +Failed to load executable: = 無法載入可執行檔: +File corrupt = 檔案損毀 +Game disc read error - ISO corrupt = 遊戲光碟讀取錯誤:ISO 損毀 +GenericAllStartupError = PPSSPP 無法以任何圖形後端啟動,請嘗試更新您的圖形和其他驅動程式 +GenericBackendSwitchCrash = PPSSPP 在啟動時當機\n\n這通常表示出現了圖形驅動程式問題,請嘗試升級圖形驅動程式\n\n圖形後端已切換: +GenericDirect3D9Error = 無法初始化圖形,請嘗試更新圖形驅動程式和 DirectX 9 執行階段\n\n要嘗試切換至 OpenGL 嗎?\n\n錯誤訊息: GenericGraphicsError = 圖形錯誤 -GenericOpenGLError = 圖形初始化失敗,請試著更新你的圖形驅動程式。\n\n你要切換到DirectX 9 試試看嗎?\n\n錯誤訊息: -GenericVulkanError = 初始化圖形失敗。 嘗試升級圖形驅動程序.\n\n您想嘗試切換到OpenGL嗎?\n\n錯誤信息: -InsufficientOpenGLDriver = 偵測到OpenGL 驅動程式的支援不足\n\n你想嘗試DirectX嗎?\n\n目前兼容DirectX 的遊戲較少,但對你的GPU而言可能是唯一的選擇。 -Just a directory. = 只是一個目錄。 -Missing key = 缺失密鑰 -MsgErrorCode = 錯誤代碼: -MsgErrorSavedataDataBroken = 保存數據已損壞. -MsgErrorSavedataMSFull = 記憶棒已滿. 檢查您的存儲空間. -MsgErrorSavedataNoData = 警告:未找到保存數據. -MsgErrorSavedataNoMS = 未插入記憶棒. -No EBOOT.PBP, misidentified game = 沒有EBOOT.PBP,錯誤識別遊戲。 -Not a valid disc image. = 無效的光盤映像. +GenericOpenGLError = 無法初始化圖形,請嘗試更新圖形驅動程式\n\n要嘗試切換至 DirectX 9 嗎?\n\n錯誤訊息: +GenericVulkanError = 無法初始化圖形,請嘗試更新圖形驅動程式\n\n要嘗試切換至 OpenGL 嗎?\n\n錯誤訊息: +InsufficientOpenGLDriver = 偵測到 OpenGL 驅動程式支援不足!\n\n您的 GPU 回報其不支援 OpenGL 2.0,要改為使用 DirectX 嗎?\n\nDirectX 目前相容的遊戲較少,但這可能是您的 GPU 的唯一選擇。\n\n造訪 https://forums.ppsspp.org 論壇以取得更多資訊。\n\n +Just a directory. = 只是一個目錄 +Missing key = 遺失金鑰 +MsgErrorCode = 錯誤碼: +MsgErrorSavedataDataBroken = 存檔資料已損毀 +MsgErrorSavedataMSFull = 記憶棒已滿,請檢查您的儲存空間 +MsgErrorSavedataNoData = 警告:找不到存檔資料 +MsgErrorSavedataNoMS = 記憶棒未插入 +No EBOOT.PBP, misidentified game = 沒有 EBOOT.PBP,無法辨識的遊戲 +Not a valid disc image. = 不是有效的光碟映像 OpenGLDriverError = OpenGL 驅動程式錯誤 -PPSSPP doesn't support UMD Music. = PPSSPP不支持UMD音樂 -PPSSPP doesn't support UMD Video. = PPSSPP不支持UMD視頻 -PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP玩 PSP遊戲,而不是PlayStation1或2遊戲. -#PPSSPP只能运行PSP游戏, 不能运行PS1或2的游戏 -PPSSPPDoesNotSupportInternet = PPSSPP目前不支援透過網路進行DLC、PSN 或更新遊戲 -PS1 EBOOTs are not supported by PPSSPP. = PPSSPP不支援PS1 EBOOTS -PSX game image detected. = 抱歉,不支援PSX遊戲 -RAR file detected (Require UnRAR) = 檔案是RAR壓縮檔。\ n請先解壓縮(需使用UnRAR)。 -RAR file detected (Require WINRAR) = 檔案是RAR壓縮檔。\ n請先解壓縮(需使用WinRAR)。 -Running slow: try frameskip, sound is choppy when slow = 運行速度慢:嘗試跳幀,聲音不連貫時慢 -Running slow: Try turning off Software Rendering = 運行緩慢:嘗試關閉“軟件渲染” -Save encryption failed. This save won't work on real PSP = 存檔加密失敗。真正的PSP將無法讀取這份存檔 -textures.ini filenames may not be cross-platform = "textures.ini"文件名可能不是跨平台的。 -This is a saved state, not a game. = 這是保存狀態,而不是遊戲。 -This is save data, not a game. = 這是保存數據,而不是遊戲。 -Unable to create cheat file, disk may be full = 無法建立金手指文件,硬碟可能已滿 -Unable to initialize rendering engine. = 無法初始化渲染引擎。 -Unable to write savedata, disk may be full = 無法記錄,硬碟可能已滿 -Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = 警告:視訊記憶體已滿,降低像素提升並切換到慢速快取模式。 -Warning: Video memory FULL, switching to slow caching mode = 警告:視訊記憶體已滿,切換到慢速快取模式。 -ZIP file detected (Require UnRAR) = 檔案是ZIP壓縮檔。\ n請先解壓縮 (需使用UnRAR)。 -ZIP file detected (Require WINRAR) = 檔案是ZIP壓縮檔。\ n請先解壓縮 (需使用WinRAR)。 +PPSSPP doesn't support UMD Music. = PPSSPP 不支援 UMD 音樂 +PPSSPP doesn't support UMD Video. = PPSSPP 不支援 UMD 影片 +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP 僅支援 PSP 遊戲,無法執行 PlayStation 1 或 PlayStation 2 遊戲 +PPSSPPDoesNotSupportInternet = PPSSPP 目前不支援連線至網際網路使用 DLC、PSN 或更新遊戲 +PS1 EBOOTs are not supported by PPSSPP. = PPSSPP 不支援 PS1 EBOOT +PSX game image detected. = 檔案為 MODE2 映像,PPSSPP 不支援 PS1 遊戲 +RAR file detected (Require UnRAR) = 檔案已壓縮 (RAR)\n請先解壓縮 (嘗試 UnRAR) +RAR file detected (Require WINRAR) = 檔案已壓縮 (RAR)\n請先解壓縮 (嘗試 WinRAR) +Running slow: try frameskip, sound is choppy when slow = 執行速度緩慢:嘗試影格跳過,速度緩慢時音效可能會斷斷續續 +Running slow: Try turning off Software Rendering = 執行速度緩慢:嘗試關閉「軟體轉譯」 +Save encryption failed. This save won't work on real PSP = 存檔加密失敗,這個存檔將無法在真實 PSP 中運作 +textures.ini filenames may not be cross-platform = 「textures.ini」檔案名稱可能無法跨平台 +This is a saved state, not a game. = 這是一個存檔,並非遊戲 +This is save data, not a game. = 這是一個存檔資料,並非遊戲 +Unable to create cheat file, disk may be full = 無法建立密技檔案,磁碟可能已滿 +Unable to initialize rendering engine. = 無法初始化轉譯引擎 +Unable to write savedata, disk may be full = 無法寫入存檔資料,磁碟可能已滿 +Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = 警告:視訊記憶體已滿,降低放大倍率並切換至慢速快取模式 +Warning: Video memory FULL, switching to slow caching mode = 警告:視訊記憶體已滿,切換至慢速快取模式 +ZIP file detected (Require UnRAR) = 檔案已壓縮 (ZIP)\n請先解壓縮 (嘗試 UnRAR) +ZIP file detected (Require WINRAR) = 檔案已壓縮 (ZIP)\n請先解壓縮 (嘗試 WinRAR) [Game] -Asia = 亞洲 -Calculate CRC = 計算CRC -ConfirmDelete = 確定 -Create Game Config = 建立遊戲配置 +Asia = 亞州 +Calculate CRC = 計算 CRC +ConfirmDelete = 刪除 +Create Game Config = 建立遊戲組態 Create Shortcut = 建立捷徑 Delete Game = 刪除遊戲 -Delete Game Config = 刪除遊戲配置 -Delete Save Data = 刪除存檔 +Delete Game Config = 刪除遊戲組態 +Delete Save Data = 刪除存檔資料 Europe = 歐洲 Game = 遊戲 Game Settings = 遊戲設定 -Homebrew = 自製游戲 +Homebrew = 自製遊戲 Hong Kong = 香港 -InstallData = 安裝數據 +InstallData = 資料安裝 Japan = 日本 -Korea = 韓國 +Korea = 南韓 MB = MB -One moment please... = 稍等一會兒... +One moment please... = 請稍候… Play = 開始遊戲 -Remove From Recent = 刪除此記錄 -SaveData = 存檔 -Setting Background = 配置背景 -Show In Folder = 顯示資料夾 +Remove From Recent = 從「最近遊玩」中移除 +SaveData = 儲存資料 +Setting Background = 設定背景 +Show In Folder = 在資料夾中顯示 USA = 美國 -Use UI background = 使用UI背景 +Use UI background = 使用 UI 背景 [Graphics] -% of the void = % 的邊框 -% of viewport = % 的視區 -%, 0:unlimited = %,0 = 無限 -(supersampling) = (超級采樣) -(upscaling) = (倍增) -1x PSP = 1倍PSP -2x = 2倍 -2x PSP = 2倍PSP -3x = 3倍 -3x PSP = 3倍PSP -4x = 4倍 -4x PSP = 4倍PSP -5x = 5倍 -5x PSP = 5倍PSP -6x PSP = 6倍PSP -7x PSP = 7倍PSP -8x = 8倍 -8x PSP = 8倍PSP -9x PSP = 9倍PSP -10x PSP = 10倍PSP -16x = 16倍 -Aggressive = 激進 -Alternative Speed = 速度控制(%,0 = 無限) -Alternative Speed 2 = 替代速度2(in %, 0 = 無限) -Anisotropic Filtering = 非等方性過濾 +% of the void = % 的無效區 +% of viewport = % 的檢視區 +%, 0:unlimited = %,0 = 無限制 +(supersampling) = (超級取樣) +(upscaling) = (放大) +1x PSP = 1× PSP +2x = 2× +2x PSP = 2× PSP +3x = 3× +3x PSP = 3× PSP +4x = 4× +4x PSP = 4× PSP +5x = 5× +5x PSP = 5× PSP +6x PSP = 6× PSP +7x PSP = 7× PSP +8x = 8× +8x PSP = 8× PSP +9x PSP = 9× PSP +10x PSP = 10× PSP +16x = 16× +Aggressive = 積極 +Alternative Speed = 替代速度 (於 %,0 = 無限制) +Alternative Speed 2 = 替代速度 2 (於 %,0 = 無限制) +Anisotropic Filtering = 非等向性過濾 +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = 長寬比 Auto = 自動 -Auto (1:1) = 自動(1:1) -Auto (same as Rendering) = 自動(同渲染) -Auto FrameSkip = 自動跳幀 -Auto Max Quality = 自動最高質量 +Auto (1:1) = 自動 (1:1) +Auto (same as Rendering) = 自動 (同於轉譯解析度) +Auto FrameSkip = 自動影格跳過 +Auto Max Quality = 自動最大品質 Auto Scaling = 自動縮放 Backend = 後端 -Balanced = 均衡 +Balanced = 平衡 Bicubic = 雙立方 -BlockTransfer Tip = 有些遊戲需要這樣才能開啟正確的圖形 -BlockTransferRequired = 警告:此遊戲需要將模擬塊傳輸模式配置為開。 -Both = 兩者 -Buffer graphics commands (faster, input lag) = 緩衝區圖形命令(更快,輸入延遲) -Buffered Rendering = 緩衝渲染 -BufferedRenderingRequired = 警告:此遊戲需要將“渲染模式”配置為“緩衝”。 +Both = 全部 +Buffer graphics commands (faster, input lag) = 緩衝圖形命令 (更快,有輸入延遲) +BufferedRenderingRequired = 警告:這個遊戲需要將「轉譯模式」設為「緩衝轉譯」 Camera = 相機 -Camera Device = 攝像頭設備 -Cardboard Screen Size = 螢幕大小(視區%) -Cardboard Screen X Shift = 水平% -Cardboard Screen Y Shift = 垂直% +Camera Device = 相機裝置 +Cardboard Screen Size = 螢幕大小 (於 % 的檢視區) +Cardboard Screen X Shift = X 移位 (於 % 的空白區) +Cardboard Screen Y Shift = Y 移位 (於 % 的空白區) Cardboard VR Settings = Google Cardboard VR 設定 -Cheats = 金手指 -CPU Core = CPU 核心模式 -Debugging = 除錯 -DefaultCPUClockRequired = 警告:此遊戲需要將CPU時鐘配置為默認值。 +Cheats = 密技 +CPU Core = CPU 核心 +Debugging = 偵錯 +DefaultCPUClockRequired = 警告:這個遊戲需要將 CPU 時脈設為預設值 Deposterize = 色調混合 -Deposterize Tip = 修復在紋理被放大時可能發生的小紋理內部毛刺 -Device = 設備 +Deposterize Tip = 修正放大化紋理中的視覺帶狀故障 +Device = 裝置 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disabled = 已禁用 -Display layout editor = 自訂版面 -Display Resolution (HW scaler) = 顯示解析度(硬體縮放) -Dump next frame to log = 將下一幀儲存到日誌 -Enable Cardboard VR = 啟用Cardboard VR +Disabled = Disabled +Display Layout && Effects = 顯示版面配置與效果 +Display Resolution (HW scaler) = 顯示解析度 (硬體縮放) +Enable Cardboard VR = 啟用 Cardboard VR FPS = FPS -Frame Rate Control = 幀速率控制 -Frame Skipping = 跳幀 -Frame Skipping Type = 跳幀類型 +Frame Rate Control = 影格速率控制 +Frame Skipping = 影格跳過 +Frame Skipping Type = 影格跳過類型 FullScreen = 全螢幕 -GPU log profiler = GPU日志分析器 -Hack Settings = 修正設定 -Hardware Tessellation = 硬體曲面細分 -Hardware Transform = 硬體幾何轉換 -hardware transform error - falling back to software = 硬體轉換錯誤,改用軟體轉換 -HardwareTessellation Tip = 使用硬體繪製曲綫,使用固定的質量 +Geometry shader culling = 幾何著色器揀選 +GPUReadbackRequired = 警告:此遊戲需要關閉「跳過 GPU 讀回」 +Hack Settings = 駭客設定 (可能會造成故障) +Hardware Tessellation = 硬體鑲嵌 +Hardware Transform = 硬體轉換 +hardware transform error - falling back to software = 硬體轉換錯誤,將回復到軟體轉換 +HardwareTessellation Tip = 使用硬體繪製曲線 High = 高 Hybrid = 混合 -Hybrid + Bicubic = 混合+雙立方 -Ignore camera notch when centering = 居中時忽略攝像頭缺口 -Internal Resolution = 內部分辨率 -Lazy texture caching = 緩慢紋理快取(提升速度) -Lazy texture caching Tip = 更快,在一些游戲裏會引起文字渲染錯誤更快, 在一些游戏里引起文字渲染错误 +Hybrid + Bicubic = 混合 + 雙立方 +Ignore camera notch when centering = 置中時忽略相機凹口 +Internal Resolution = 內部解析度 +Lazy texture caching = 消極式紋理快取 (加速) +Lazy texture caching Tip = 更快,但在某些遊戲中可能會造成文字問題 Linear = 線性 Low = 低 -LowCurves = 樣條函數/貝茲曲線品質 -LowCurves Tip = 此選項將顯著提高/降低渲染樣條和貝塞爾曲線的質量 -Lower resolution for effects (reduces artifacts) = 降低效果的解析度(減少失真) +LowCurves = 曲線/貝茲曲線品質 +LowCurves Tip = 僅供少數遊戲使用,控制曲線平滑度 +Lower resolution for effects (reduces artifacts) = 降低效果解析度 (降低失真) Manual Scaling = 手動縮放 Medium = 中 Mode = 模式 -Must Restart = 你必須重新啟動 PPSSPP,此更改才會生效 -Native device resolution = 原生裝置的解析度 +Must Restart = 您必須重新啟動 PPSSPP 以使這項變更生效 +Native device resolution = 原生裝置解析度 Nearest = 鄰近取樣 -No buffer = 不緩衝 -Non-Buffered Rendering = 非緩衝渲染(跳過緩衝效果,較快速) -None = 關閉 -Number of Frames = 幀數 +No buffer = 無緩衝 +Skip Buffer Effects = 跳過緩衝區效果 +None = 無 +Number of Frames = 影格數 Off = 關閉 OpenGL = OpenGL -Overlay Information = 覆蓋訊息 -Partial Stretch = 局部拉伸 -Percent of FPS = FPS百分比 -Performance = 性能 -Postprocessing effect = 後處理效果 -Postprocessing Shader = 後期處理著色器 -Recreate Activity = 重新創建活動 -Render duplicate frames to 60hz = 渲染重複幀至60Hz -RenderDuplicateFrames Tip = 在以較低幀速率運行的遊戲中可以使幀速率更平滑 -Rendering Mode = 渲染模式 -Rendering Resolution = 渲染解析度 -RenderingMode NonBuffered Tip = 較快速,但在某些遊戲中可能什麼都不會顯示 -Retain changed textures = 保留更改紋理(有時更慢) -RetainChangedTextures Tip = 許多遊戲的速度變慢,但某些遊戲則變快許多 +Overlay Information = 覆疊資訊 +Partial Stretch = 部分延展 +Percent of FPS = FPS 百分比 +Performance = 效能 +Postprocessing shaders = 後處理著色器 +Recreate Activity = 重新建立活動 +Render duplicate frames to 60hz = 轉譯重複影格至 60 Hz +RenderDuplicateFrames Tip = 可以使以較低影格速率執行的遊戲更加順暢 +Rendering Mode = 轉譯模式 +Rendering Resolution = 轉譯解析度 +RenderingMode NonBuffered Tip = 更快,但在某些遊戲中可能無法繪圖 Rotation = 旋轉 Safe = 安全 -Screen layout = 屏幕佈局 Screen Scaling Filter = 螢幕縮放濾鏡 -Show Debug Statistics = 顯示除錯數據 +Show Debug Statistics = 顯示偵錯統計資料 Show FPS Counter = 顯示 FPS 計數器 -Simulate Block Transfer = 模擬塊傳送的影響 -Software Rendering = 軟體渲染 -Software Skinning = 減少繪圖調用(提升速度) -SoftwareSkinning Tip = 在使用高級皮膚技術的遊戲中減少繪圖和更快,但有些遊戲更慢 +Skip GPU Readbacks = 跳過 GPU 讀回 +Software Rendering = 軟體轉譯 (慢) +Software Skinning = 軟體除皮 +SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 Speed = 速度 -Stretching = 拉伸 -Texture Filter = 紋理過濾 -Texture Filtering = 紋理過濾 +Speed Hacks = 速度駭客 (可能會造成轉譯錯誤!) +Stereo display shader = 立體顯示著色器 +Stereo rendering = 立體轉譯 +Stretch = 延伸 +Texture Filter = 紋理濾鏡 +Texture Filtering = 紋理濾鏡 Texture Scaling = 紋理縮放 Texture Shader = 紋理著色器 -Turn off Hardware Tessellation - unsupported = 關閉“硬件曲面細分”:不支持 -Unlimited = 無限 -Up to 1 = 上到1 -Up to 2 = 上到2 -Upscale Level = 縮放倍率 -Upscale Type = 縮放類型 -UpscaleLevel Tip = CPU的負擔大,某些縮放可能會延遲,以免遊戲不流暢 -Use all displays = 使用所有顯示 +Turn off Hardware Tessellation - unsupported = 關閉「硬體鑲嵌」:不支援 +Unlimited = 無限制 +Up to 1 = 最多至 1 +Up to 2 = 最多至 2 +Upscale Level = 放大層級 +Upscale Type = 放大類型 +UpscaleLevel Tip = CPU 負載過重 - 部分縮放可能會延遲以避免間斷 +Use all displays = 使用所有顯示器 Vertex Cache = 頂點快取 -VertexCache Tip = 速度更快,但可能會造成螢幕暫時閃爍 +VertexCache Tip = 更快,但可能會造成暫時閃爍 VSync = 垂直同步 Vulkan = Vulkan Window Size = 視窗大小 xBRZ = xBRZ [InstallZip] -Delete ZIP file = 刪除ZIP檔案 +Delete ZIP file = 刪除 ZIP 檔案 Install = 安裝 -Install game from ZIP file? = 從ZIP檔案安裝遊戲? -Install textures from ZIP file? = 從ZIP文件安裝紋理? -Installed! = 安裝完成! -Texture pack doesn't support install = 紋理包不支持安裝 -Zip archive corrupt = ZIP檔案損壞 -Zip file does not contain PSP software = ZIP文件不包含PSP軟件 +Install game from ZIP file? = 從 ZIP 檔案安裝遊戲? +Install textures from ZIP file? = 從 ZIP 檔案安裝紋理? +Installed! = 已安裝! +Texture pack doesn't support install = 紋理套件不支援安裝 +Zip archive corrupt = ZIP 封存損毀 +Zip file does not contain PSP software = ZIP 檔案不包含 PSP 軟體 [KeyMapping] -Autoconfigure = 自動配置 -Autoconfigure for device = 設備自動配置 -Bind All = 全部綁定 +Autoconfigure = 自動設定 +Autoconfigure for device = 自動設定裝置 +Bind All = 全部繫結 Clear All = 全部清除 -Default All = 全部恢復預設 -Map a new key for = 你按下的按鈕將會對應到此功能: -Map Key = 按鍵映射 -Map Mouse = 鼠標映射 -Replace = 替換 +Default All = 重設為預設值 +Map a new key for = 對應新按鍵: +Map Key = 對應按鍵 +Map Mouse = 對應滑鼠 +Replace = 取代 Show PSP = 顯示 PSP -You can press ESC to cancel. = 您可以按Esc取消。 +You can press ESC to cancel. = 您可以按下 ESC 取消 [MainMenu] -Browse = 瀏覽... -Buy PPSSPP Gold = 購買PPSSPP黃金版 -Choose folder = 選擇文件夾 -Credits = 製作團隊 -PPSSPP Homebrew Store = 從PPSSPP自製游戲商店下載 +Browse = 瀏覽… +Buy PPSSPP Gold = 購買黃金版 +Choose folder = 選擇資料夾 +Credits = 製作名單 +PPSSPP Homebrew Store = PPSSPP 自製遊戲商店 Exit = 離開 -Game Settings = 遊戲設定 +Game Settings = 設定 Games = 遊戲 -Give PPSSPP permission to access storage = 給予PPSSPP存取權限 -Homebrew & Demos = 自製遊戲和試玩 -How to get games = 如何獲得遊戲 -How to get homebrew & demos = 如何獲得自製遊戲和試玩 -Load = 載入遊戲... -Loading... = 載入中... -PinPath = 標記 -PPSSPP can't load games or save right now = PPSSPP現在無法載入遊戲或存檔 -Recent = 最近執行的遊戲 -SavesAreTemporary = PPSSPP正在保存在臨時存儲中 -SavesAreTemporaryGuidance = 將PPSSPP提取到某個地方以永久保存 +Give PPSSPP permission to access storage = 授與 PPSSPP 權限以存取儲存空間 +Homebrew & Demos = 自製遊戲與試玩 +How to get games = 如何取得遊戲? +How to get homebrew & demos = 如何取得自製遊戲與試玩? +Load = 載入… +Loading... = 正在載入… +PinPath = 釘選 +PPSSPP can't load games or save right now = PPSSPP 目前無法載入或儲存遊戲 +Recent = 最近遊玩 +SavesAreTemporary = PPSSPP 正在儲存於暫時儲存空間 +SavesAreTemporaryGuidance = 將 PPSSPP 擷取至其他位置以永久儲存 SavesAreTemporaryIgnore = 忽略警告 -UnpinPath = 取消標記 -UseBrowseOrLoad = 瀏覽以選擇文件夾,或者加載以載入遊戲文件 -www.ppsspp.org = www.ppsspp.org +UnpinPath = 取消釘選 +UseBrowseOrLoad = 使用「瀏覽」以選擇資料夾,或「載入」以選擇檔案 +www.ppsspp.org = 官方網站 [MainSettings] -Audio = 聲音設定 -Controls = 控制器設定 -Graphics = 圖形設定 -Networking = 網路連線 -Search = 搜索 -System = 系統設定 +Audio = 音訊 +Controls = 控制 +Graphics = 圖形 +Networking = 網路 +System = 系統 Tools = 工具 +Search = 搜尋 [MappableControls] -Alt speed 1 = 自定義速度1 -Alt speed 2 = 自定義速度2 -An.Down = 左搖桿:下 -An.Left = 左搖桿:左 -An.Right = 左搖桿:右 -An.Up = 左搖桿:上 -Analog limiter = 搖桿限制器 -Analog Stick = 搖桿 -Audio/Video Recording = 音頻/視頻錄製 +Alt speed 1 = 替代速度 1 +Alt speed 2 = 替代速度 2 +An.Down = 類比搖桿:下 +An.Left = 類比搖桿:左 +An.Right = 類比搖桿:右 +An.Up = 類比搖桿:上 +Analog limiter = 類比限制器 +Analog Stick = 類比搖桿 +Audio/Video Recording = 音訊/視訊錄製 AxisSwap = 軸交換 -Circle = 圈 -Cross = 叉 -Custom 1 = 預設1 -Custom 10 = 預設10 -Custom 2 = 預設2 -Custom 3 = 預設3 -Custom 4 = 預設4 -Custom 5 = 預設5 -Custom 6 = 預設6 -Custom 7 = 預設7 -Custom 8 = 預設8 -Custom 9 = 預設9 -D-pad down = 方向鍵:下 -D-pad left = 方向鍵:左 -D-pad right = 方向鍵:右 -D-pad up = 方向鍵:上 -DevMenu = 開發者選單 -Display Landscape = 顯示橫向 -Display Landscape Reversed = 顯示橫向反轉 -Display Portrait = 顯示縱向 -Display Portrait Reversed = 顯示縱向反轉 -Double tap button = 雙擊鍵 -Down = 方向鍵:下 +Circle = ○ +Cross = × +Custom 1 = 自訂 1 +Custom 2 = 自訂 2 +Custom 3 = 自訂 3 +Custom 4 = 自訂 4 +Custom 5 = 自訂 5 +Custom 6 = 自訂 6 +Custom 7 = 自訂 7 +Custom 8 = 自訂 8 +Custom 9 = 自訂 9 +Custom 10 = 自訂 10 +D-pad down = 方向鍵:下 +D-pad left = 方向鍵:左 +D-pad right = 方向鍵:右 +D-pad up = 方向鍵:上 +DevMenu = 開發選單 +Double tap button = 點兩下按鈕 +Down = 方向鍵:下 Dpad = 方向鍵 -Frame Advance = 逐幀播放 -Hold = 短按電源鍵 -Home = Home +Frame Advance = 逐影格 +Hold = 固定 +Home = PS 按鈕 L = L -Left = 方向鍵:左 -Load State = 載入即時存檔 -Mute toggle = 靜音 -Next Slot = 下一槽 +Left = 方向鍵:左 +Load State = 載入存檔 +Mute toggle = 靜音切換 +Next Slot = 下一存檔插槽 None = 無 -Note = Note -OpenChat = 打開聊天 +Note = 聲音按鈕 +OpenChat = 開啟聊天 Pause = 暫停 R = R -RapidFire = 連射 +RapidFire = 快速開火 Record = 錄製 -Remote hold = 長按電源鍵 -Rewind = 倒回 -Right = 方向鍵:右 -Right Analog Stick = 右搖桿 +Remote hold = 遠端固定 +Rewind = 倒轉 +Right = 方向鍵:右 +Right Analog Stick = 右類比搖桿 RightAn.Down = 右搖桿:下 RightAn.Left = 右搖桿:左 RightAn.Right = 右搖桿:右 RightAn.Up = 右搖桿:上 -Rotate Analog (CCW) = 旋轉模擬(CCW) -Rotate Analog (CW) = 旋轉模擬(CW) -Save State = 即時存檔 -Screen = 屏幕 -Screenshot = 屏幕截圖 +Rotate Analog (CCW) = 旋轉類比 (CCW) +Rotate Analog (CW) = 旋轉類比 (CW) +Save State = 儲存存檔 +Screen = 螢幕 +Screenshot = 螢幕截圖 Select = 選擇 SpeedToggle = 速度切換 -Square = 正方 +Square = □ Start = 開始 Swipe Down = 向下滑動 Swipe Left = 向左滑動 Swipe Right = 向右滑動 Swipe Up = 向上滑動 -tap to customize = 點擊並自定義 -Texture Dumping = 紋理轉儲 -Texture Replacement = 紋理替換 -Toggle Fullscreen = 切換全屏 +tap to customize = 點選以自訂 +Texture Dumping = 紋理傾印 +Texture Replacement = 紋理取代 +Toggle Fullscreen = 切換全螢幕 Toggle mode = 切換模式 -Triangle = 三角形 -Fast-forward = 解除速限 +Triangle = △ +Fast-forward = 快轉 Up = 方向鍵:上 -Vol + = 音量+ -Vol - = 音量- -Wlan = 無綫網絡 - -[MemStick] -Already contains PSP data = 已包含PSP數據 -Create or Choose a PSP folder = 創建或選擇PSP文件夾 -Current = 目前 -DataCanBeShared = 數據可在PPSSPP普通版/黃金版共用 -DataCannotBeShared = 數據無法在PPSSPP普通版/黃金版共用! -DataWillBeLostOnUninstall = 警告! 卸載PPSSPP會丟失數據! -DataWillStay = 卸載PPSSPP會保留數據 -Done! = 完成! -EasyUSBAccess = 輕鬆USB訪問 -Failed to move some files! = 無法移動部分文件! -Failed to save config = 無法保存配置 -Free space = 可用空間 -Manually specify PSP folder = 手動指定PSP文件夾 -MemoryStickDescription = 選擇PSP文件存放位置(記憶棒) -Move Data = 移動PSP數據 -Selected PSP Data Folder = 選擇PSP數據文件夾 -No data will be changed = 數據不會更改 -PPSSPP will restart after the change = 完成配置后會重啓PPSSPP -Skip for now = 暫時跳過 -Starting move... = 開始移動... -That folder doesn't work as a memstick folder. = 所選文件夾無法作爲記憶棒目錄您选择的文件夹无法作为记忆棒目录。 -USBAccessThrough = USB連接時請打開 Android/data/org.ppsspp.ppsspp/files -USBAccessThroughGold = USB連接時請打開 Android/data/org.ppsspp.ppssppgold/files -Use App Private Data = 在APP内置的目錄中保存 -Use PSP folder at root of storage = 在手機目錄中保存PSP文件 -Welcome to PPSSPP! = 歡迎使用PPSSPP! -WhatsThis = 這個配置有什麽用? +Vol + = 音量 + +Vol - = 音量 - +Wlan = WLAN +Display Landscape = 顯示器橫向 +Display Landscape Reversed = 顯示器橫向反轉 +Display Portrait = 顯示器直向 +Display Portrait Reversed = 顯示器直向反轉 [Networking] -AdHoc Server = Ad hoc服務器 -AdhocServer Failed to Bind Port = 無法綁定Adhoc服務器端口 -AM: Data from Unknown Port = AM:來自未知端口的數據 +AdHoc Server = 臨機操作伺服器 +AdhocServer Failed to Bind Port = 臨機操作伺服器無法繫結連接埠 +AM: Data from Unknown Port = AM:來自不明連接埠的資料 Auto = 自動 -Bottom Center = 中間下面 -Bottom Left = 下左面 -Bottom Right = 右下面 -Center Left = 中間左面 -Center Right = 中間右面 -Change Mac Address = 改變 Mac 網路位址 -Change proAdhocServer Address = 改變PRO Adhoc網路位址(localhost = 多個實例) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +Bottom Center = 正下 +Bottom Left = 左下 +Bottom Right = 右下 +Center Left = 正左 +Center Right = 正右 +Change Mac Address = 變更 MAC 位址 +ChangeMacSaveConfirm = 產生新的 MAC 位址? +ChangeMacSaveWarning = 某些遊戲在載入儲存資料時會驗證 MAC 位址,這可能會損毀舊存檔 +Change proAdhocServer Address = 變更 PRO 臨機操作伺服器 IP 位址 (本機主機 = 多重執行個體) Chat = 聊天 Chat Button Position = 聊天按鈕位置 Chat Here = 在這裡聊天 -Chat message = 聊天消息 +Chat message = 聊天訊息 Chat Screen Position = 聊天畫面位置 -Disconnected from AdhocServer = 與 dhoc服務器斷開連接 -DNS Error Resolving = DNS錯誤解決 -Enable built-in PRO Adhoc Server = 啟用內建PRO Adhoc伺服器 -Enable network chat = 啟用網絡聊天 -Enable networking = 啟用網路連線/無線區域網路(測試) -Enable UPnP = 啟用UPnP(需要幾秒鐘來檢測) +Disconnected from AdhocServer = 從臨機操作伺服器中斷連線 +DNS Error Resolving = DNS 解析錯誤 +Enable built-in PRO Adhoc Server = 啟用內建 PRO 臨機操作伺服器 +Enable network chat = 啟用網路聊天 +Enable networking = 啟用網路功能/WLAN (測試版,可能損毀遊戲) +Enable UPnP = 啟用 UPnP (需要數秒鐘來偵測) EnableQuickChat = 啟用快速聊天 -Enter a new PSP nickname = 輸入新的PSP暱稱 -Enter Quick Chat 1 = 輸入快速聊天1 -Enter Quick Chat 2 = 輸入快速聊天2 -Enter Quick Chat 3 = 輸入快速聊天3 -Enter Quick Chat 4 = 輸入快速聊天4 -Enter Quick Chat 5 = 輸入快速聊天5 -Error = Error -Failed to Bind Localhost IP = 無法綁定本地主機IP -Failed to Bind Port = 無法綁定端口 -Failed to connect to Adhoc Server = 無法連接Adhoc服務器 -Forced First Connect = 強制首次連接(更快的連接) -GM: Data from Unknown Port = GM:數據來自未知端口 -Hostname = 主機名 -Invalid IP or hostname = 無效的IP或主機名 -Minimum Timeout = 最小超時(以毫秒為單位,0=默認) -Misc = 其他(默認= PSP兼容性) +Enter a new PSP nickname = 輸入新的 PSP 暱稱 +Enter Quick Chat 1 = 輸入快速聊天 1 +Enter Quick Chat 2 = 輸入快速聊天 2 +Enter Quick Chat 3 = 輸入快速聊天 3 +Enter Quick Chat 4 = 輸入快速聊天 4 +Enter Quick Chat 5 = 輸入快速聊天 5 +Error = 錯誤 +Failed to Bind Localhost IP = 無法繫結本機主機 IP +Failed to Bind Port = 無法繫結連接埠 +Failed to connect to Adhoc Server = 無法連線至臨機操作伺服器 +Forced First Connect = 強制首次連線 (更快連線) +GM: Data from Unknown Port = GM:來自不明連接埠的資料 +Hostname = 主機名稱 +Invalid IP or hostname = 無效的 IP 或主機名稱 +Minimum Timeout = 最小逾時 (單位為毫秒,0 = 預設) +Misc = 雜項 (預設 = PSP 相容性) Network Initialized = 網路已初始化 None = 無 -Please change your Port Offset = 請更改您的端口偏移 -Port offset = 端口偏移 (0 = PSP 實機兼容) -Open PPSSPP Multiplayer Wiki Page = 打開PPSSPP多人百科頁面 -#打开PPSSPP多人联机百科页面 -proAdhocServer Address: = Ad hoc服務器地址: -Quick Chat 1 = 快速聊天1 -Quick Chat 2 = 快速聊天2 -Quick Chat 3 = 快速聊天3 -Quick Chat 4 = 快速聊天4 -Quick Chat 5 = 快速聊天5 +Please change your Port Offset = 請變更您的連接埠位移 +Port offset = 連接埠位移 (0 = PSP 相容性) +Open PPSSPP Multiplayer Wiki Page = 開啟 PPSSPP 多人遊戲維基頁面 +proAdhocServer Address: = 臨機操作伺服器位址: +Quick Chat 1 = 快速聊天 1 +Quick Chat 2 = 快速聊天 2 +Quick Chat 3 = 快速聊天 3 +Quick Chat 4 = 快速聊天 4 +Quick Chat 5 = 快速聊天 5 QuickChat = 快速聊天 -Send = 發送 -Send Discord Presence information = 發送Discord "Rich Presence" information -#发送Discord"在线状态"信息 -Top Center = 中間上面 -Top Left = 左上面 -Top Right = 右上面 -Unable to find UPnP device = 找不到UPnP設備 -UPnP (port-forwarding) = UPnP(端口轉發) -UPnP need to be reinitialized = UPnP需要重新初始化 -UPnP use original port = UPnP使用原始端口(已啟用=PSP兼容性) -Validating address... = 驗證地址... +Send = 傳送 +Send Discord Presence information = 傳送 Discord「Rich Presence」資訊 +Top Center = 正上 +Top Left = 左上 +Top Right = 右上 +Unable to find UPnP device = 找不到 UPnP 裝置 +UPnP (port-forwarding) = UPnP (連接埠轉送) +UPnP need to be reinitialized = UPnP 需要重新初始化 +UPnP use original port = UPnP 使用原始連接埠 (已啟用 = PSP 相容性) +Validating address... = 正在驗證位址… WLAN Channel = WLAN 頻道 -You're in Offline Mode, go to lobby or online hall = 您現在是離綫模式,請進入房間或在綫大廳 +You're in Offline Mode, go to lobby or online hall = 您目前處於離線模式,請前往大廳或線上大廳 [Pause] -Cheats = 金手指 +Cheats = 密技 Continue = 繼續 -Create Game Config = 建立遊戲配置 -Delete Game Config = 刪除遊戲配置 -Exit to menu = 返回主選單 +Create Game Config = 建立遊戲組態 +Delete Game Config = 刪除遊戲組態 +Exit to menu = 返回選單 Game Settings = 遊戲設定 Load State = 載入存檔 -Rewind = 倒回 -Save State = 即時存檔 +Rewind = 倒轉 +Save State = 儲存存檔 Settings = 設定 -Switch UMD = 切換光碟 -Undo last load = 撤銷加載 -Undo last save = 撤銷保存 +Switch UMD = 切換 UMD +Undo last load = 復原上次載入 +Undo last save = 復原上次儲存 [PostShaders] -(duplicated setting, previous slider will be used) = (配置重複, 將使用上面滑塊的值) -4xHqGLSL = 4×HQ GLSL -5xBR = 5xBR -5xBR-lv2 = 5xBR-lv2 +(duplicated setting, previous slider will be used) = (重複的設定,將使用上一個滑桿) +4xHqGLSL = 4xHQ 畫素藝術放大 +5xBR = 5xBR 畫素藝術放大 +5xBR-lv2 = 5xBR-lv2 畫素藝術放大 AAColor = AA-Color Amount = 數量 -Animation speed (0 -> disable) = 動畫速度(0->禁用) -Black border = 黑色描邊 -Bloom = 汎光 +Black border = 黑色框線 +Bloom = 光圈 Brightness = 亮度 Cartoon = 卡通 -CatmullRom = Bicubic 雙三插值縮放 -ColorCorrection = 顔色修正 +ColorCorrection = 色彩修正 +ColorPreservation = 色彩保留 Contrast = 對比度 -CRT = CRT 掃描綫 -FXAA = FXAA (快速近似抗鋸齒) -Gamma = 伽馬 -Grayscale = 灰度图 -Intensity = 强度 -InverseColors = 反色 -MitchellNetravali = Bicubic 雙三插值縮放 -Natural = 自然色 -NaturalA = 自然色-無模糊 +CRT = CRT 掃描線 +FXAA = FXAA 消除鋸齒 +Gamma = 色差補正 +GreenLevel = 綠色色階 +Intensity = 濃度 +LCDPersistence = LCD Persistence +Natural = 自然色彩 +NaturalA = 自然色彩 (無模糊) Off = 關閉 -Power = 效果强度 -PSPColor = PSP顔色 -Saturation = 色彩 -Scanlines = 掃描綫(CRT) -Sharpen = 銳化 -SSAA(Gauss) = Supersampling AA(超級采樣抗鋸齒:高斯) +Power = 強度 +PSPColor = PSP 色彩 +RedBlue = 紅藍眼鏡 +Saturation = 飽和度 +Scanlines = 掃描線 (CRT) +Sharpen = 銳利化 +SideBySide = 並排 (SBS) +SSAA(Gauss) = 超級取樣 AA (高斯) Tex4xBRZ = 4xBRZ TexMMPX = MMPX -UpscaleSpline36 = Spline36縮放 -VideoSmoothingAA = VideoSmoothingAA(視頻平滑抗鋸齒) -Vignette = 光暈 +UpscaleSpline36 = Spline36 放大 +VideoSmoothingAA = 視訊平滑 AA +Vignette = 暈影 +Animation speed (0 -> disable) = 動畫速度 (0 -> 停用) +CatmullRom = 雙立方 (卡特姆 - 羅姆) 放大 +MitchellNetravali = 雙立方 (密契爾 - 內拉瓦利) 放大 [PSPCredits] -all the forum mods = 論壇上所有的mod -build server = 編譯服務器 +all the forum mods = 所有論壇模組 +build server = 組建伺服器 Buy Gold = 購買黃金版 -check = 也歡迎你試用海豚模擬器,最好用的Wii/GC 模擬器 -CheckOutPPSSPP = 查閲 PPSSPP, 一款超棒的PSP模擬器:https://www.ppsspp.org/ +check = 同樣歡迎使用 Dolphin 模擬器,這是最棒的 Wii/GC 模擬器 +CheckOutPPSSPP = 體驗 PPSSPP,一款絕佳的 PSP 模擬器:https://www.ppsspp.org/ contributors = 參與者: created = 作者: Discord = Discord -info1 = PPSSPP僅限教學用途 -info2 = 請確認你有權使用該遊戲, -info3 = 例如持有該遊戲的正版光碟, -info4 = 或是透過PSP於PSN商店購買數位版。 -info5 = PSP®是索尼公司的註冊商標。 -iOS builds = iOS builds -license = PPSSPP是遵循GPL 2.0+授權條款的自由軟體 -list = 網站上有相容性列表、官方論壇以及開發動態 -PPSSPP Forums = PPSSPP官方論壇 -Privacy Policy = 隱私政策 -Share PPSSPP = 分享PPSSPP +info1 = PPSSPP 僅適用於教育用途, +info2 = 請確保您擁有遊戲的版權, +info3 = 您擁有遊戲的 UMD 光碟, +info4 = 或是透過 PSP 在 PSN 商店中購買數位版。 +info5 = PSP® 是 Sony, Inc 的註冊商標 +iOS builds = iOS 組建 +license = PPSSPP 是遵循 GPL 2.0+ 授權條款的自由軟體 +list = 瞭解相容性清單、官方論壇和開發資訊 +PPSSPP Forums = PPSSPP 論壇 +Privacy Policy = 隱私權政策 +Share PPSSPP = 分享 PPSSPP specialthanks = 特別感謝: -specialthanksKeithGalocy = 的硬件,建議,他來自NVIDIA -specialthanksMaxim = 的出色Atrac3 +解碼 -testing = 負責測試 -this translation by = 譯者: -title = 快速、方便攜帶的PSP模擬器 -tools = 使用自由工具: +specialthanksKeithGalocy = 的硬體和建議,他來自 NVIDIA +specialthanksMaxim = 的出色的解碼器工作 +testing = 測試人員 +this translation by = 正體中文翻譯: +title = 快速、方便攜帶的 PSP 模擬器 +tools = 使用的自由工具: # Add translators or contributors who translated PPSSPP into your language here. # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. -translators1 = sum2012, kaienfr, raven02, aquanull, xiwo4525 -translators2 = wuspring, zzq920817, W-MS, xzapk, Arthur200000 -translators3 = Playhi, PeaceShi, Nargacuga, driver1998 -translators4 = xujibbs +translators1 = sum2012, xujibbs, leoxxx, Adeptus2 +translators2 = +translators3 = +translators4 = translators5 = translators6 = -Twitter @PPSSPP_emu = Twitter @PPSSPP_emu -website = 歡迎參觀我們的網站: -written = 使用C++編寫以保證移植性和速度 +Twitter @PPSSPP_emu = Twitter +website = 歡迎造訪我們的網站: +written = 使用 C++ 編寫,以保證建置速度和相容性 + +[MemStick] +Already contains PSP data = 已包含 PSP 資料 +Create or Choose a PSP folder = 建立或選擇 PSP 資料夾 +Current = 目前 +DataCanBeShared = 資料可在 PPSSPP 標準版/黃金版之間共用 +DataCannotBeShared = 資料無法在 PPSSPP 標準版/黃金版之間共用! +DataWillBeLostOnUninstall = 警告!資料會在解除安裝 PPSSPP 後遺失! +DataWillStay = 資料會在解除安裝 PPSSPP 後保留 +Done! = 完成! +EasyUSBAccess = USB 輕鬆存取 +Failed to move some files! = 無法移動部分檔案! +Failed to save config = 無法儲存組態 +Free space = 可用空間 +Manually specify PSP folder = 手動指定 PSP 資料夾 +MemoryStickDescription = 選擇 PSP 資料存放位置 (記憶棒) +Move Data = 移動資料 +Selected PSP Data Folder = 選取的 PSP 資料資料夾 +Skip for now = 暫時跳過 +No data will be changed = 沒有要變更的資料 +PPSSPP will restart after the change = PPSSPP 將在完成變更後重新啟動 +Starting move... = 開始移動… +That folder doesn't work as a memstick folder. = 這個資料夾無法作為記憶棒資料夾正常運作 +USBAccessThrough = 透過 USB 存取 Android/data/org.ppsspp.ppsspp/files +USBAccessThroughGold = 透過 USB 存取 Android/data/org.ppsspp.ppssppgold/files +Use App Private Data = 使用應用程式私人資料夾 +Use PSP folder at root of storage = 使用儲存空間 PSP 資料夾 +Welcome to PPSSPP! = 歡迎使用 PPSSPP! +WhatsThis = 這是什麼? [RemoteISO] Browse Games = 瀏覽遊戲 -Local Server Port = 本地服務器端口 -Manual Mode Client = 手動模式客戶端 -Remote disc streaming = 遠程光盤流 -Remote Port = 遠端埠 +Local Server Port = 本機伺服器連接埠 +Manual Mode Client = 手動設定用戶端 +Remote disc streaming = 遠端光碟串流 +Remote Port = 遠端連接埠 Remote Server = 遠端伺服器 -Remote Subdirectory = 遠程子目錄 -RemoteISODesc = 您最近列表中的遊戲將被共享 -RemoteISOLoading = 已連接,正在加載遊戲列表... -RemoteISOScanning = 掃描...單擊服務器設備上的“共享遊戲” -RemoteISOScanningTimeout = 正在掃描...檢查您桌面的防火牆配置 -RemoteISOWifi = 注意:將兩個設備都連接到同一Wi-Fi網絡 -RemoteISOWinFirewall = 警告:Windows防火牆阻止共享 -Settings = 設定值 -Share Games (Server) = 分享遊戲(服務器) -Share on PPSSPP startup = 分享PPSSPP啟動 -Stop Sharing = 停止分享 -Stopping.. = 正在停止... +Remote Subdirectory = 遠端子目錄 +RemoteISODesc = 「最近遊玩」清單中的遊戲將被共用 +RemoteISOLoading = 已連線,正在載入遊戲清單… +RemoteISOScanning = 正在掃描… 在您的伺服器裝置上按一下「共用遊戲」 +RemoteISOScanningTimeout = 正在掃描… 檢查您的桌面防火牆設定 +RemoteISOWifi = 注意:將兩部裝置皆連線至同一 Wi-Fi 網路 +RemoteISOWinFirewall = 警告:Windows 防火牆已封鎖共用 +Settings = 設定 +Share Games (Server) = 共用遊戲 (伺服器) +Share on PPSSPP startup = PPSSPP 啟動時共用 +Stop Sharing = 停止共用 +Stopping.. = 正在停止… [Reporting] -Bad = 壞 -FeedbackCRCCalculating = 光碟CRC: 計算中... -FeedbackCRCValue = 光碟CRC: %1 -FeedbackDelayInfo = 您的數據正在後台提交. -FeedbackDesc = 模擬的效果怎麼樣?說給我們聽聽! -FeedbackDisabled = 兼容性服務器報告必須啟用. -FeedbackIncludeCRC = 注意:電池將用於發送光盤CRC -FeedbackIncludeScreen = 包括屏幕截圖 -FeedbackSubmitDone = 您的數據已提交. -FeedbackSubmitFail = 無法將數據提交到服務器。 嘗試更新PPSSPP。 -FeedbackThanks = 感謝您的反饋意見! -Gameplay = 遊戲過程 +Bad = 不佳 +FeedbackCRCCalculating = 光碟 CRC:正在計算… +FeedbackCRCValue = 光碟 CRC:%1 +FeedbackDelayInfo = 您的資料正在背景提交 +FeedbackDesc = 模擬效果如何?說給我們聽聽! +FeedbackDisabled = 必須啟用相容性伺服器回報 +FeedbackIncludeCRC = 注意:傳送光碟 CRC 將會損耗電池電力 +FeedbackIncludeScreen = 包含螢幕截圖 +FeedbackSubmitDone = 您的資料已提交 +FeedbackSubmitFail = 無法將資料提交至伺服器,嘗試更新 PPSSPP +FeedbackThanks = 感謝您的意見反應 +Gameplay = 遊戲歷程 Graphics = 圖形 -Great = 很好 -In-game = 在遊戲中 -In-game Description = 能進入遊戲玩,但太多問題 +Great = 絕佳 +In-game = 遊戲內 +In-game Description = 可以進入遊戲,但存在很多錯誤 Menu/Intro = 選單/簡介 -Menu/Intro Description = 無法進入遊戲本身 -Nothing = 沒畫面 -Nothing Description = 完全壞了 -OK = 好 -Open Browser = 打開瀏覽器 +Menu/Intro Description = 無法進入遊戲 +Nothing = 沒有畫面 +Nothing Description = 完全損毀 +OK = 良好 +Open Browser = 開啟報告網站 Overall = 整體 Perfect = 完美 -Perfect Description = 完美模擬整個游戲 - 太棒了! +Perfect Description = 完美模擬整個遊戲 - 太棒了! Plays = 可玩 -Plays Description = 基本模擬整個游戲,但有時會出現故障 -ReportButton = 報告反饋 -Show disc CRC = 顯示光碟CRC +Plays Description = 可以遊玩,但可能會出現故障 +ReportButton = 回報意見反應 +Show disc CRC = 顯示光碟 CRC Speed = 速度 -Submit Feedback = 提交反饋 -SuggestionConfig = 請參閱網站上的報告以了解正確的配置。 -SuggestionCPUSpeed0 = 禁用鎖定的CPU速度配置。 -SuggestionDowngrade = 降級到較舊的PPSSPP版本(請報告此錯誤)。 -SuggestionsFound = 其他用戶報告了更好的結果。 點擊“查看反饋”以獲取更多詳細信息。 -SuggestionsNone = 其他用戶也不能運行該游戲。 -SuggestionsWaiting = 提交並檢查其他用戶的反饋... -SuggestionUpgrade = 升級到更新的PPSSPP版本。 -SuggestionVerifyDisc = 檢查您的ISO是否是光盤的良好副本。 +Submit Feedback = 提交意見反應 +SuggestionConfig = 參閱網站上的報告以瞭解最佳設定 +SuggestionCPUSpeed0 = 停用鎖定的 CPU 速度設定 +SuggestionDowngrade = 降級為舊版 PPSSPP (請回報此錯誤) +SuggestionsFound = 其他使用者已回報了更佳的結果,點選「檢視意見反映」以取得更多詳細資料 +SuggestionsNone = 這個遊戲在其他使用者的裝置上也無法運作 +SuggestionsWaiting = 正在提交並檢查其他使用者的意見反應… +SuggestionUpgrade = 升級至新版 PPSSPP 組建 +SuggestionVerifyDisc = 檢查 ISO 是否為您光碟的良好複本 Unselected Overall Description = 這個遊戲的模擬效果如何? -View Feedback = 查看所有反饋 +View Feedback = 檢視所有意見反應 [Savedata] Date = 日期 -Filename = 文件名 -No screenshot = 沒有截圖 -None yet. Things will appear here after you save. = 暫無。在你存檔之後這裡才會出現數據。 -Nothing matching '%1' was found. = 沒有找到符合'%1'的結果。 -Save Data = 存檔資料 -Save States = 即時存檔資料 -Savedata Manager = 管理存檔資料 -Showing matches for '%1'. = 找到符合'%1'的搜尋結果。 +Filename = 檔案名稱 +No screenshot = 沒有螢幕截圖 +None yet. Things will appear here after you save. = 尚無,將在存檔後出現新項目 +Nothing matching '%1' was found. = 找不到與「%1」相符的項目 +Save Data = 儲存資料 +Save States = 存檔 +Savedata Manager = 儲存資料管理員 +Showing matches for '%1'. = 顯示與「%1」相符的項目 Size = 大小 [Screen] -Cardboard VR OFF = Cardboard VR關閉 -Chainfire3DWarning = 警告:偵測到Chainfire3D,可能造成問題 -Failed to load state = 無法載入快速存檔 -Failed to save state = 無法儲存快速存檔 -fixed = 速度:固定 -GLToolsWarning = 警告:偵測到GLTools,可能造成問題 -In menu = In menu -Load savestate failed = 無法載入快速存檔 -Loaded State = 已載入即時存檔 -Loaded. Game may refuse to save over different savedata. = 已加載。游戲可能無法保存在別的存檔。 -Loaded. Game may refuse to save over newer savedata. = 已加載。游戲可能無法保存在進度提前的存檔。 -Loaded. Save in game, restart, and load for less bugs. = 已加載。 保存在遊戲中,重新啟動並加載,以減少錯誤。 -LoadStateDoesntExist = 無法載入:存檔不存在! -LoadStateWrongVersion = 無法載入:存檔為舊版的PPSSPP的! -norewind = 倒带即時存檔不可用 -Playing = 游戲中 -PressESC = 按下ESC鍵以暫停遊戲 -replaceTextures_false = 不再替換紋理. -replaceTextures_true = 啟用紋理替換. -Save State Failed = 即時存檔失敗! -Saved State = 即時存檔完成 -saveNewTextures_false = 紋理保存已禁用. -saveNewTextures_true = 紋理現在將保存到您的存儲中. -SpeedCustom2 = 速度:備用2 +Cardboard VR OFF = Cardboard VR 關閉 +Chainfire3DWarning = 警告:偵測到 Chainfire3D,可能會造成問題 +Failed to load state = 無法載入存檔 +Failed to save state = 無法儲存存檔 +fixed = 速度:替代 +GLToolsWarning = 警告:偵測到 GLTools,可能會造成問題 +In menu = 選單中 +Load savestate failed = 無法載入存檔 +Loaded State = 存檔已載入 +Loaded. Save in game, restart, and load for less bugs. = 已載入,在遊戲中儲存、重新啟動,然後載入,將會減少錯誤 +Loaded. Game may refuse to save over different savedata. = 已載入,遊戲可能會拒絕覆寫不同的存檔 +Loaded. Game may refuse to save over newer savedata. = 已載入,遊戲可能會拒絕覆寫較新的存檔 +LoadStateDoesntExist = 無法載入存檔:存檔不存在! +LoadStateWrongVersion = 無法載入存檔:存檔僅適用於舊版 PPSSPP! +norewind = 沒有可用的倒轉存檔 +Playing = 正在遊玩 +PressESC = 按下 ESC 以開啟暫停選單 +replaceTextures_false = 紋理將不再被取代 +replaceTextures_true = 紋理取代已啟用 +Save State Failed = 無法儲存存檔! +Saved State = 已存檔 +saveNewTextures_false = 紋理儲存已停用 +saveNewTextures_true = 紋理將儲存至您的儲存空間 +SpeedCustom2 = 速度:替代 2 standard = 速度:標準 -State load undone = 撤銷載入存檔 -Untitled PSP game = 無標題的PSP遊戲 - -[Search] -Clear filter = 清楚篩選結果 -Filter = 篩選 -Filtering settings by '%1' = 配置篩選'%1' -Find settings = 搜索配置 -No settings matched '%1' = 未找到配置'%1' +State load undone = 存檔載入復原 +Untitled PSP game = 未命名 PSP 遊戲 [Store] -Already Installed = 已安裝完成 +Already Installed = 已安裝 Connection Error = 連線錯誤 Install = 安裝 -Launch Game = 開始遊戲 -Loading... = 載入中... +Launch Game = 啟動遊戲 +Loading... = 正在載入… MB = MB Size = 大小 Uninstall = 解除安裝 [SysInfo] -%d (%d per core, %d cores) = %d (每核心 %d 綫程, %d 核心) -%d bytes = %d 字節 -(none detected) = (未檢測到) +%0.2f Hz = %0.2f Hz +%d (%d per core, %d cores) = %d (每核心 %d 執行緒,%d 核心) +%d bytes = %d 位元組 +%d Hz = %d Hz +(none detected) = (未偵測到) 3D API = 3D API ABI = ABI -API Version = API版本 -Audio Information = 音頻信息 -Board = 主板 -Build Config = 編譯配置 -Build Configuration = 編譯配置 -Built by = 編譯者 -Core Context = 核心上下文 +API Version = API 版本 +Audio Information = 音訊資訊 +Board = 主機板 +Build Config = 組建組態 +Build Configuration = 組建組態 +Built by = 建置者 +Core Context = 核心內容 Cores = 核心數 -CPU Extensions = CPU擴展 -CPU Information = CPU信息 -CPU Name = CPU名稱 -D3DCompiler Version = D3DCompiler版本 -Debug = 調試 -Debugger Present = 調試器已連接 -Device Info = 設備信息 -Directories = 路徑 -Display Color Formats = 顯示顔色格式 -Display Information = 顯示信息 -Driver Version = 驅動程序版本 -EGL Extensions = EGL擴展 -Frames per buffer = 每緩存區幀數 -GPU Information = GPU信息 -High precision float range = 高精度浮點範圍 -High precision int range = 高精度整數範圍 +CPU Extensions = CPU 擴充 +CPU Information = CPU 資訊 +CPU Name = CPU 名稱 +D3DCompiler Version = D3DCompiler 版本 +Debug = 偵錯 +Debugger Present = 偵錯工具呈現 +Depth buffer format = 深度緩衝區格式 +Device Info = 裝置資訊 +Directories = 目錄 +Display Information = 顯示器資訊 +Driver bugs = 驅動程式錯誤 +Driver Version = 驅動程式版本 +EGL Extensions = EGL 擴充 +Frames per buffer = 每緩衝區影格數 +GPU Information = GPU 資訊 +High precision float range = 高精確度浮點數範圍 +High precision int range = 高精確度整數範圍 Lang/Region = 語言/區域 -Memory Page Size = 内存頁大小 -Native Resolution = 原生分辨率 -OGL Extensions = OGL 擴展 -OpenGL ES 2.0 Extensions = OpenGL ES 2.0擴展 -OpenGL ES 3.0 Extensions = OpenGL ES 3.0擴展 -OpenGL Extensions = OpenGL擴展 -Optimal frames per buffer = 最佳每緩存區幀數 -Optimal sample rate = 最佳采樣率 -OS Information = OS信息 -PPSSPP build = PPSSPP編譯版本 -Refresh rate = 刷新率 -Release = 發佈 -RW/RX exclusive = RW/RX獨占 -Sample rate = 采樣率 -Shading Language = 著色語言 -Storage = 存儲 -Sustained perf mode = 持久性能模式 -System Information = 系統信息 +Memory Page Size = 記憶體分頁大小 +Native Resolution = 原生解析度 +No GPU driver bugs detected = 未偵測到 GPU 驅動程式錯誤 +OGL Extensions = OGL 擴充 +OpenGL ES 2.0 Extensions = OpenGL ES 2.0 擴充 +OpenGL ES 3.0 Extensions = OpenGL ES 3.0 擴充 +OpenGL Extensions = OpenGL 擴充 +Optimal frames per buffer = 最佳每緩衝區影格數 +Optimal sample rate = 最佳取樣率 +OS Information = OS 資訊 +PPSSPP build = PPSSPP 組建 +Refresh rate = 重新整理速率 +Release = 發行版本 +RW/RX exclusive = RW/RX 排除 +Sample rate = 取樣率 +Shading Language = 網底語言 +Storage = 儲存空間 +Sustained perf mode = 持續效能模式 +System Information = 系統資訊 System Name = 系統名稱 System Version = 系統版本 -Threads = 綫程數 -Vendor = 供應商 -Vendor (detected) = 供應商 (已檢測到的) -Version Information = 版本信息 -Vulkan Extensions = Vulkan擴展 -Vulkan Features = Vulkan特性 -Driver bugs = 驅動錯誤 -No GPU driver bugs detected = 未檢測到GPU驅動錯誤 +Threads = 執行緒 +Vendor = 廠商 +Vendor (detected) = 廠商 (偵測到) +Version Information = 版本資訊 +Vulkan Extensions = Vulkan 擴充 +Vulkan Features = Vulkan 功能 +Display Color Formats = 顯示器色彩格式 [System] -(broken) = (壞了) -12HR = 12小時 -24HR = 24小時 +(broken) = (已損毀) +12HR = 12 小時制 +24HR = 24 小時制 Auto = 自動 -Auto Load Savestate = 自動加載保存狀態 -AVI Dump started. = AVI轉儲開始 -AVI Dump stopped. = AVI轉儲停止 -Cache ISO in RAM = 將整個ISO檔暫存於記憶體中 -Change CPU Clock = 調整CPU時鐘(不穩定) -Color Tint = 色調 -Color Saturation = 顔色飽和度 -Error: load undo state is from a different game = 錯誤: 撤回的即時存檔來自不同游戲 -Failed to load state for load undo. Error in the file system. = 無法撤銷加載的即時存檔,文件系統有錯誤。 -Floating symbols = 漂浮的符號 -Memory Stick folder = 更改記憶棒文件夾 -Memory Stick size = 更改記憶棒大小(GB) -Change Nickname = 更改別名 -ChangingMemstickPath = 游戲存檔、即時存檔以及其他數據不會被複製到新路徑。\n\n確定要修改記憶棒文件嗎? -ChangingMemstickPathInvalid = 目標路徑不能用於保存記憶棒數據。 -Cheats = 金手指 -Clear Recent = 清除最近的游戲 -Clear Recent Games List = 清除最近遊戲清單 -Clear UI background = 清除背景 -Confirmation Button = 確認鍵 +Auto Load Savestate = 自動載入存檔 +AVI Dump started. = AVI 傾印已啟動 +AVI Dump stopped. = AVI 傾印已停止 +Cache ISO in RAM = 將完整 ISO 快取於 RAM +Change CPU Clock = 變更模擬 PSP CPU 時脈 (不穩定) +Game crashed = 遊戲已當機 +Language = 語言 +Memory Stick folder = 記憶棒資料夾 +Memory Stick size = 記憶棒大小 +Change Nickname = 變更暱稱 +ChangingMemstickPath = 遊戲、存檔和其他資料將不會複製到這個資料夾\n\n要變更記憶棒資料夾嗎? +ChangingMemstickPathInvalid = 這個路徑將無法用於儲存記憶棒檔案 +Cheats = 密技 +Clear Recent = 清除「最近遊玩」 +Clear Recent Games List = 清除「最近遊玩」清單 +Clear UI background = 清除 UI 背景 +Confirmation Button = 確認按鈕 Date Format = 日期格式 Day Light Saving = 日光節約時間 -DDMMYYYY = DDMMYYYY -Decrease size = 減少尺寸 -Developer Tools = 開發者工具 -Display Extra Info = 顯示額外信息 -Display Games on a grid = 以方格顯示“游戲” -Display Homebrew on a grid = 以方格顯示 "自製游戲" -Display Recent on a grid = 以方格顯示最近的游戲 -Dynarec (JIT) = 動態重編譯(JIT) +DDMMYYYY = 日/月/年 +Decrease size = 減小尺寸 +Developer Tools = 開發人員工具 +Display Extra Info = 顯示額外資訊 +Display Games on a grid = 以格狀顯示「遊戲」 +Display Homebrew on a grid = 以格狀顯示「自製遊戲與試玩」 +Display Recent on a grid = 以格狀顯示「最近遊玩」 +Dynarec (JIT) = 動態重新編譯 (JIT) Emulation = 模擬 -Enable Cheats = 啓用金手指 -Enable Compatibility Server Reports = 向伺服器回報相容性問題 -Failed to load state. Error in the file system. = 無法讀取即時存檔。檔案系統錯誤。 -Failed to save state. Error in the file system. = 無法儲存即時存檔。檔案系統錯誤。 -Fast (lag on slow storage) = 快速 (存取較慢的系統仍會延遲) -Fast Memory = 快速記憶體存取(不穩定) -Force real clock sync (slower, less lag) = 強制實際時鐘同步(速度較慢,但較少延遲) -frames, 0:off = 幀,0 = 關閉 -Games list settings = 游戲列表配置 +Enable Cheats = 啟用密技 +Enable Compatibility Server Reports = 啟用相容性伺服器回報 +Error: load undo state is from a different game = 錯誤:載入復原存檔來自不同遊戲 +Failed to load state. Error in the file system. = 無法載入存檔,檔案系統錯誤 +Failed to save state. Error in the file system. = 無法儲存存檔,檔案系統錯誤 +Failed to load state for load undo. Error in the file system. = 無法載入復原存檔,檔案系統錯誤 +Fast (lag on slow storage) = 快速 (慢速儲存體延遲) +Fast Memory = 快速記憶體 (不穩定) +Floating symbols = 浮動符號 +Force real clock sync (slower, less lag) = 強制真實時脈同步 (更慢,減少延遲) +frames, 0:off = 影格,0 = 關閉 +Games list settings = 遊戲清單設定 General = 一般 -Grid icon size = 倍率圖標尺寸 -Help the PPSSPP team = 幫助PPSSPP團隊 -Host (bugs, less lag) = 主機(較少延遲,但可能造成問題;有助於魔法少女小圓) -Ignore bad memory accesses = 忽略錯誤的內存訪問 -Increase size = 增加大小 -Interpreter = 解釋器 -IO timing method = I/O計時方法 -IR Interpreter = IR解釋器 -Memory Stick Folder = 記憶棒文件夾 -Memory Stick inserted = 插入記憶棒 -MHz, 0:default = MHz,預設為0 -MMDDYYYY = MMDDYYYY -Moving background = 動態壁紙 -Newest Save = 最新存礑 -No animation = 靜態壁紙 -Not a PSP game = 不是PSP遊戲 +Grid icon size = 格狀圖示大小 +Help the PPSSPP team = 協助 PPSSPP 團隊 +Host (bugs, less lag) = 主機 (更多錯誤,減少延遲) +Ignore bad memory accesses = 忽略損毀的記憶體存取 +Increase size = 加大尺寸 +Interpreter = 解譯器 +IO timing method = I/O 計時方法 +IR Interpreter = IR 解譯器 +Memory Stick Folder = 記憶棒資料夾 +Memory Stick inserted = 記憶棒插入 +MHz, 0:default = MHz,0 = 預設 +MMDDYYYY = 月/日/年 +Moving background = 動態背景 +Newest Save = 最新存檔 +No animation = 靜態背景 +Not a PSP game = 這不是 PSP 遊戲 Off = 關閉 -Oldest Save = 最早存礑 -Path does not exist! = 路徑不存在! -PSP Memory Stick = PSP記憶棒 -PSP Model = PSP機型 +Oldest Save = 最舊存檔 +Path does not exist! = 路徑不存在! +PSP Memory Stick = PSP 記憶棒 +PSP Model = PSP 型號 PSP Settings = PSP 設定 PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = 最近的游戲 -Record Audio = 錄音 -Record Display = 錄製畫面 -Reset Recording on Save/Load State = 在保存/加載狀態下重置記錄 -Restore Default Settings = 還原出廠設定 -Rewind Snapshot Frequency = 快照倒回頻率 -Save path in installed.txt = 存檔路徑在installed.txt -Save path in My Documents = 存檔路徑在我的文件 -Savestate Slot = 即時存檔插槽 -Savestate slot backups = 即時存檔插槽備份 -Screenshots as PNG = PNG格式截圖 -Set UI background... = 配置UI背景... -Show ID = 顯示ID -Show Memory Stick folder = 顯示記憶棒文件夾 -Show region flag = 顯示區域標誌 -Simulate UMD delays = 模擬UMD延遲(修正紙箱戰機W) -Slot 1 = 插槽1 -Slot 2 = 插槽2 -Slot 3 = 插槽3 -Slot 4 = 插槽4 -Slot 5 = 插槽5 -Storage full = 存儲容量已滿 -Sustained performance mode = 持續性能模式 -Theme = 主題 +Recent games = 最近遊戲 +Record Audio = 錄製音訊 +Record Display = 錄製視訊 +Reset Recording on Save/Load State = 儲存/載入存檔時重設錄製 +Restore Default Settings = 將 PPSSPP 設定重設為預設值 +Rewind Snapshot Frequency = 倒轉快照頻率 +Save path in installed.txt = 儲存路徑於 installed.txt +Save path in My Documents = 儲存路徑於「我的文件」 +Savestate Slot = 存檔插槽 +Savestate slot backups = 存檔插槽備份 +Screenshots as PNG = 以 PNG 格式儲存螢幕截圖 +Set UI background... = 設定 UI 背景… +Show ID = 顯示 ID +Show region flag = 顯示區域旗幟 +Simulate UMD delays = 模擬 UMD 延遲 +Slot 1 = 插槽 1 +Slot 2 = 插槽 2 +Slot 3 = 插槽 3 +Slot 4 = 插槽 4 +Slot 5 = 插槽 5 +Storage full = 儲存空間已滿 +Sustained performance mode = 持續效能模式 Time Format = 時間格式 -UI = 用戶界面 -UI background animation = UI背景效果 -UI Sound = 介面聲音 -undo %c = 備用 %c +UI = UI +UI Sound = UI 音效 +UI background animation = UI 背景動畫 +undo %c = 備份 %c USB = USB -Use Lossless Video Codec (FFV1) = 使用無損視訊轉碼器(FFV1) -Use O to confirm = 使用O確認 -Use output buffer (with overlay) for recording =使用輸出緩衝區(帶有覆蓋)進行記錄 -Use system native keyboard = 使用系統本機鍵盤 -Use X to confirm = 使用X確認 +Use Lossless Video Codec (FFV1) = 使用不失真視訊轉碼器 (FFV1) +Use O to confirm = 使用 O 按鈕 +Use output buffer (with overlay) for recording = 為錄製使用輸出緩衝區 (覆疊) +Use system native keyboard = 使用系統原生鍵盤 +Use X to confirm = 使用 X 按鈕 VersionCheck = 檢查 PPSSPP 新版本 -WARNING: Android battery save mode is on = 警告:Android省電模式已開啟 +WARNING: Android battery save mode is on = 警告:Android 省電模式已開啟 WARNING: Battery save mode is on = 警告:省電模式已開啟 Waves = 波浪 -YYYYMMDD = YYYYMMDD +YYYYMMDD = 年/月/日 Theme = 主題 -Show Memory Stick folder = 顯示記憶棒文件夾 +Color Tint = 色彩濃淡 +Color Saturation = 色彩飽和度 +Show Memory Stick folder = 顯示記憶棒資料夾 + +[Themes] +Default = 預設 [TextureShaders] Off = 關閉 @@ -1209,29 +1201,41 @@ TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ -[Themes] -Default = 默認 +[Search] +No settings matched '%1' = 沒有與「%1」相符的設定 +Filtering settings by '%1' = 依「%1」篩選設定 +Find settings = 尋找設定 +Filter = 篩選器 +Clear filter = 清除篩選器 + +[Upgrade] +Details = 詳細資料 +Dismiss = 關閉 +Download = 下載 +New version of PPSSPP available = PPSSPP 有可用的新版本 [UI Elements] %1 button = %1 按鈕 -%1 checkbox = %1 複選框 +%1 checkbox = %1 核取方塊 %1 choice = %1 選擇 -%1 heading = %1 heading -%1 radio button = %1 單選按鈕 -%1 text field = %1 文本域 -Choices: = 選擇: -List: = 列表: -Progress: %1% = 進程: %1% -Screen representation = 屏幕表現 -[Upgrade] -Details = 詳情 -Dismiss = 忽略 -Download = 下載 -New version of PPSSPP available = 已有新版的PPSSPP +%1 heading = %1 標題 +%1 radio button = %1 選項按鈕 +%1 text field = %1 文字欄位 +Choices: = 選擇: +List: = 清單: +Progress: %1% = 進度:%1% +Screen representation = 螢幕呈現 -[Search] -Filtering settings by '%1' = 配置篩選 '%1' -Find settings = 搜索配置 -Filter = 篩選 -Clear filter = 清楚篩選 -No settings matched '%1' = 未找到配置 '%1' +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Map controller movements to keys = Map controller movements to keys +Motion needed to generate action = Motion needed to generate action +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index a125a09206..b0e48dabb8 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -28,13 +28,18 @@ Name=Vignette Author=Henrik Fragment=vignette.fsh Vertex=fxaa.vsh -[Grayscale] -Name=Grayscale -Author=Henrik -Fragment=grayscale.fsh -Vertex=fxaa.vsh +SettingName1=Power +SettingDefaultValue1=0.6 +SettingMaxValue1=2.0 +SettingMinValue1=0.1 +SettingStep1=0.1 +SettingName2=Aspect +SettingDefaultValue2=1.0 +SettingMaxValue2=2.0 +SettingMinValue2=0.5 +SettingStep2=0.1 [Bloom] -Name=Bloom +Name=Bloom Shader Fragment=bloom.fsh Vertex=fxaa.vsh SettingName1=Amount @@ -52,13 +57,8 @@ Vertex=fxaa.vsh SettingName1=Amount SettingDefaultValue1=1.5 SettingMaxValue1=3.0 -SettingMinValue1=1.0 +SettingMinValue1=0.1 SettingStep1=0.1 -[InverseColors] -Name=Inverse Colors -Author=Henrik -Fragment=inversecolors.fsh -Vertex=fxaa.vsh [Scanlines] Name=Scanlines (CRT) Fragment=scanlines.fsh @@ -186,3 +186,35 @@ Name=MMPX (2x) Author=Morgan McGuire and Mara Gagiu Compute=tex_mmpx.csh Scale=2 +[RedBlue] +Type=StereoToMono +Name=Red/Blue glasses (anaglyph) +Author=Henrik Rydgård +SettingName1=ColorPreservation +SettingDefaultValue1=0.5 +SettingMaxValue1=1.0 +SettingMinValue1=0.0 +SettingStep1=0.05 +SettingName2=GreenLevel +SettingDefaultValue2=0.5 +SettingMaxValue2=1.0 +SettingMinValue2=0.0 +SettingStep2=0.05 +Fragment=stereo_red_blue.fsh +Vertex=fxaa.vsh +[SideBySide] +Type=StereoToMono +Name=SideBySide Stereo +Author=Henrik Rydgård +Fragment=stereo_sbs.fsh +Vertex=fxaa.vsh +[LCDPersistence] +Name=LCD Persistence +Fragment=persistence.fsh +Vertex=fxaa.vsh +UsePreviousFrame=true +SettingName1=Strength +SettingDefaultValue1=0.4 +SettingMaxValue1=0.8 +SettingMinValue1=0.3 +SettingStep1=0.05 \ No newline at end of file diff --git a/assets/shaders/grayscale.fsh b/assets/shaders/grayscale.fsh deleted file mode 100644 index f309204e12..0000000000 --- a/assets/shaders/grayscale.fsh +++ /dev/null @@ -1,16 +0,0 @@ -// Simple grayscale shader - -#ifdef GL_ES -precision mediump float; -precision mediump int; -#endif - -uniform sampler2D sampler0; -varying vec2 v_texcoord0; - -void main() { - vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz; - float luma = dot(rgb, vec3(0.299, 0.587, 0.114)); - gl_FragColor.rgb = vec3(luma, luma, luma); - gl_FragColor.a = 1.0; -} diff --git a/assets/shaders/inversecolors.fsh b/assets/shaders/inversecolors.fsh deleted file mode 100644 index c6367ca2fd..0000000000 --- a/assets/shaders/inversecolors.fsh +++ /dev/null @@ -1,19 +0,0 @@ -// Simple false color shader - -#ifdef GL_ES -precision mediump float; -precision mediump int; -#endif - -uniform sampler2D sampler0; -varying vec2 v_texcoord0; - -void main() { - vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz; - float luma = dot(rgb, vec3(0.299, 0.587, 0.114)); - vec3 gray = vec3(luma, luma, luma) - 0.5; - rgb -= vec3(0.5, 0.5, 0.5); - - gl_FragColor.rgb = mix(rgb, gray, 2.0) + 0.5; - gl_FragColor.a = 1.0; -} diff --git a/assets/shaders/persistence.fsh b/assets/shaders/persistence.fsh new file mode 100644 index 0000000000..9be51d8225 --- /dev/null +++ b/assets/shaders/persistence.fsh @@ -0,0 +1,14 @@ +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform sampler2D sampler0; +uniform sampler2D sampler2; +uniform vec4 u_setting; +varying vec2 v_texcoord0; + +void main() { + gl_FragColor.rgb = mix(texture2D(sampler0, v_texcoord0.xy).rgb, texture2D(sampler2, v_texcoord0.xy).rgb, u_setting.x); + gl_FragColor.a = 1.0; +} diff --git a/assets/shaders/stereo_red_blue.fsh b/assets/shaders/stereo_red_blue.fsh new file mode 100644 index 0000000000..1ad875b6b3 --- /dev/null +++ b/assets/shaders/stereo_red_blue.fsh @@ -0,0 +1,31 @@ +// Red/Blue glasses stereo, also known as anaglyph. +// +// NOTE: Will only be compiled for Vulkan so doesn't follow all the usual conventions. + +uniform sampler2DArray sampler0; +varying vec2 v_texcoord0; + +uniform vec4 u_setting; + +void main() { + float saturation = u_setting.x; + float greenMix = u_setting.y; + + // To be adjusted. Used to desaturate colors. + vec3 grayDot = vec3(0.35, 0.5, 0.15); + // And these are the output color channels. + vec3 red = vec3(1.0, 0.0, 0.0); + vec3 blue = vec3(0.0, greenMix, 1.0); + + vec3 left = texture(sampler0, vec3(v_texcoord0, 0.0)).xyz; + vec3 right = texture(sampler0, vec3(v_texcoord0, 1.0)).xyz; + + float leftGray = dot(left, grayDot); + float rightGray = dot(right, grayDot); + + vec3 leftColor = mix(vec3(leftGray), left, saturation) * red; + vec3 rightColor = mix(vec3(rightGray), right, saturation) * blue; + + gl_FragColor.rgb = leftColor + rightColor; + gl_FragColor.a = 1.0; +} diff --git a/assets/shaders/stereo_sbs.fsh b/assets/shaders/stereo_sbs.fsh new file mode 100644 index 0000000000..c308f3aa0d --- /dev/null +++ b/assets/shaders/stereo_sbs.fsh @@ -0,0 +1,18 @@ +// Side by side stereo, useful for old 3D TVs. +// +// NOTE: Will only be compiled for Vulkan so doesn't follow all the usual conventions. + +uniform sampler2DArray sampler0; +varying vec2 v_texcoord0; + +uniform vec4 u_setting; + +void main() { + if (v_texcoord0.x < 0.5) { + gl_FragColor.rgb = texture(sampler0, vec3(v_texcoord0.x * 2.0, v_texcoord0.y, 0.0)).xyz; + } else { + gl_FragColor.rgb = texture(sampler0, vec3((v_texcoord0.x - 0.5) * 2.0, v_texcoord0.y, 1.0)).xyz; + } + + gl_FragColor.a = 1.0; +} diff --git a/assets/shaders/vignette.fsh b/assets/shaders/vignette.fsh index 7e2c92e69a..b4dc2b41c9 100644 --- a/assets/shaders/vignette.fsh +++ b/assets/shaders/vignette.fsh @@ -8,9 +8,15 @@ precision mediump int; uniform sampler2D sampler0; varying vec2 v_texcoord0; +uniform vec4 u_setting; + void main() { - float vignette = 1.1 - 0.6 * (dot(v_texcoord0 - 0.5, v_texcoord0 - 0.5) * 2.0); + vec2 diff = v_texcoord0 - 0.5; + diff.x *= u_setting.y; + diff.y /= u_setting.y; + float vignette = 1.0 - min(1.0, u_setting.x * (dot(diff, diff) * 2.0)); vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz; + rgb *= vignette; gl_FragColor.rgb = vignette * rgb; gl_FragColor.a = 1.0; } diff --git a/assets/ui_atlas.meta b/assets/ui_atlas.meta index 32d31ed132..88c386e491 100644 Binary files a/assets/ui_atlas.meta and b/assets/ui_atlas.meta differ diff --git a/assets/ui_atlas.zim b/assets/ui_atlas.zim index 85517eb137..465d54e6f0 100644 Binary files a/assets/ui_atlas.zim and b/assets/ui_atlas.zim differ diff --git a/build.gradle b/build.gradle index bfad5c1419..d9fc3ebd95 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:7.3.1' } } diff --git a/ext/armips b/ext/armips index b4335f04fa..6719edebaa 160000 --- a/ext/armips +++ b/ext/armips @@ -1 +1 @@ -Subproject commit b4335f04fa62c1b4f7833c70fbb15505b6772274 +Subproject commit 6719edebaae03330ee5441d9b28280672edf00d5 diff --git a/ext/libarmips.vcxproj b/ext/libarmips.vcxproj index c0484e63d1..bd9f5c9911 100644 --- a/ext/libarmips.vcxproj +++ b/ext/libarmips.vcxproj @@ -502,6 +502,12 @@ + + + + + + @@ -554,6 +560,12 @@ + + + + + + diff --git a/ext/libarmips.vcxproj.filters b/ext/libarmips.vcxproj.filters index 61282421bb..4a9b54143c 100644 --- a/ext/libarmips.vcxproj.filters +++ b/ext/libarmips.vcxproj.filters @@ -31,6 +31,9 @@ {d1037c70-bb54-46fc-8b0c-a47c4ea4a252} + + {496988ff-1b2f-4046-bc02-b5ad9a1952b4} + @@ -183,6 +186,24 @@ Core + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + @@ -341,5 +362,23 @@ Core + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + + + Archs\SuperH + \ No newline at end of file diff --git a/ext/libzip/config.h b/ext/libzip/config.h index a5d26ea015..77c373b611 100644 --- a/ext/libzip/config.h +++ b/ext/libzip/config.h @@ -27,11 +27,11 @@ #endif #ifndef MS_UWP #define HAVE_FILENO -#define HAVE_FSEEKO -#define HAVE_FTELLO #define HAVE_GETPROGNAME #endif #ifndef _WIN32 +#define HAVE_FSEEKO +#define HAVE_FTELLO #define HAVE_LOCALTIME_R #define HAVE_MKSTEMP 1 #endif diff --git a/ext/libzstd.vcxproj b/ext/libzstd.vcxproj index 7cd642f51c..68dadeded9 100644 --- a/ext/libzstd.vcxproj +++ b/ext/libzstd.vcxproj @@ -231,7 +231,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -250,7 +250,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug true @@ -267,7 +267,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug true @@ -284,7 +284,7 @@ Level4 - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug true @@ -304,7 +304,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false MultiThreaded true @@ -330,7 +330,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded @@ -356,7 +356,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded @@ -382,7 +382,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded diff --git a/ext/native/tools/atlastool/atlastool.vcxproj b/ext/native/tools/atlastool/atlastool.vcxproj index 65b315ebdc..9ad9d35117 100644 --- a/ext/native/tools/atlastool/atlastool.vcxproj +++ b/ext/native/tools/atlastool/atlastool.vcxproj @@ -97,7 +97,6 @@ true ../../../../;../../ext;../../;../../../../ext;../prebuilt;../../../../ext/zstd/lib MultiThreaded - false Console diff --git a/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so b/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so index 784337e64e..c93b4e444d 100644 Binary files a/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so and b/ext/openxr/libs/pico/arm64-v8a/libopenxr_loader.so differ diff --git a/ext/openxr/openxr.h b/ext/openxr/openxr.h index 02ec7cfbcb..88772f7f4e 100644 --- a/ext/openxr/openxr.h +++ b/ext/openxr/openxr.h @@ -2,7 +2,7 @@ #define OPENXR_H_ 1 /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -25,12 +25,15 @@ extern "C" { ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) // OpenXR current version number. -#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 14) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 24) #define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) #define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) #define XR_VERSION_PATCH(version) (uint32_t)((uint64_t)(version) & 0xffffffffULL) +#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 + + #if !defined(XR_NULL_HANDLE) #if (XR_PTR_SIZE == 8) && XR_CPP_NULLPTR_SUPPORTED #define XR_NULL_HANDLE nullptr @@ -120,7 +123,6 @@ XR_DEFINE_HANDLE(XrActionSet) #define XR_MAX_PATH_LENGTH 256 #define XR_MAX_STRUCTURE_NAME_SIZE 64 #define XR_MAX_RESULT_STRING_SIZE 64 -#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 #define XR_MAX_ACTION_SET_NAME_SIZE 64 #define XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE 128 #define XR_MAX_ACTION_NAME_SIZE 64 @@ -181,13 +183,37 @@ typedef enum XrResult { XR_ERROR_LOCALIZED_NAME_DUPLICATED = -48, XR_ERROR_LOCALIZED_NAME_INVALID = -49, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING = -50, + XR_ERROR_RUNTIME_UNAVAILABLE = -51, XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000, XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001, XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT = -1000039001, XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT = -1000053000, XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT = -1000055000, + XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT = -1000066000, + XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT = -1000097000, + XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT = -1000097001, + XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT = -1000097002, + XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT = -1000097003, + XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT = -1000097004, + XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT = -1000097005, XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -1000101000, XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB = -1000108000, + XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB = -1000113000, + XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB = -1000113001, + XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB = -1000113002, + XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB = -1000113003, + XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB = -1000118000, + XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB = -1000118001, + XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB = -1000118002, + XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB = -1000118003, + XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB = -1000118004, + XR_ERROR_UNKNOWN_PASSTHROUGH_FB = -1000118050, + XR_ERROR_RENDER_MODEL_KEY_INVALID_FB = -1000119000, + XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020, + XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000, + XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001, + XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001, + XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002, XR_RESULT_MAX_ENUM = 0x7FFFFFFF } XrResult; @@ -242,17 +268,6 @@ typedef enum XrStructureType { XR_TYPE_ACTIONS_SYNC_INFO = 61, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO = 62, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO = 63, - //pico add new type - XR_TYPE_EVENT_CONTROLLER_STATE_CHANGED = 1200006064, - XR_TYPE_EVENT_SEETHROUGH_STATE_CHANGED = 1200006065, - XR_TYPE_EVENT_HARDIPD_STATE_CHANGED = 1200006066, - XR_TYPE_EVENT_KEY_EVENT = 1200006067, - XR_TYPE_EVENT_FOVEATION_LEVEL_CHANGED = 1200006068, - XR_TYPE_EVENT_FRUSTUM_STATE_CHANGED = 1200006069, - XR_TYPE_EVENT_RENDER_TEXTURE_CHANGED = 1200006070, - XR_TYPE_EVENT_TARGET_FRAME_RATE_STATE_CHANGED = 1200006071, - XR_TYPE_EVENT_MRC_STATUS_CHANGED = 1200006072, - XR_TYPE_EVENT_REFRESH_RATE_CHANGE = 1200006073, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR = 1000006000, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR = 1000008000, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR = 1000010000, @@ -291,9 +306,14 @@ typedef enum XrStructureType { XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR = 1000034000, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT = 1000039000, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT = 1000039001, + XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB = 1000040000, + XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB = 1000041001, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT = 1000046000, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX = 1000048004, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT = 1000049000, + XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT = 1000049001, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT = 1000049002, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT = 1000049003, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT = 1000051000, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002, @@ -317,16 +337,118 @@ typedef enum XrStructureType { XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT = 1000066000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000, + XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000, + XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT = 1000078000, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000, + XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR = 1000090001, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR = 1000090003, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR = 1000091000, + XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT = 1000097000, + XR_TYPE_SCENE_CREATE_INFO_MSFT = 1000097001, + XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT = 1000097002, + XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT = 1000097003, + XR_TYPE_SCENE_COMPONENTS_MSFT = 1000097004, + XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT = 1000097005, + XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT = 1000097006, + XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT = 1000097007, + XR_TYPE_SCENE_OBJECTS_MSFT = 1000097008, + XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT = 1000097009, + XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT = 1000097010, + XR_TYPE_SCENE_PLANES_MSFT = 1000097011, + XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT = 1000097012, + XR_TYPE_SCENE_MESHES_MSFT = 1000097013, + XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT = 1000097014, + XR_TYPE_SCENE_MESH_BUFFERS_MSFT = 1000097015, + XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT = 1000097016, + XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT = 1000097017, + XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT = 1000097018, + XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT = 1000098000, + XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT = 1000098001, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 1000101000, + XR_TYPE_VIVE_TRACKER_PATHS_HTCX = 1000103000, + XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX = 1000103001, + XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC = 1000104000, + XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC = 1000104001, + XR_TYPE_FACIAL_EXPRESSIONS_HTC = 1000104002, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB = 1000108000, + XR_TYPE_HAND_TRACKING_MESH_FB = 1000110001, + XR_TYPE_HAND_TRACKING_SCALE_FB = 1000110003, + XR_TYPE_HAND_TRACKING_AIM_STATE_FB = 1000111001, + XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB = 1000112000, + XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB = 1000113004, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB = 1000113003, + XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB = 1000113007, + XR_TYPE_SPACE_COMPONENT_STATUS_FB = 1000113001, + XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB = 1000113005, + XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB = 1000113006, + XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB = 1000114000, + XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB = 1000114001, + XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB = 1000114002, + XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB = 1000115000, + XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB = 1000116009, + XR_TYPE_KEYBOARD_TRACKING_QUERY_FB = 1000116004, + XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB = 1000116002, + XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB = 1000117001, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB = 1000118000, + XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001, + XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002, + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003, + XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB = 1000118004, + XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB = 1000118005, + XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB = 1000118021, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB = 1000118022, + XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB = 1000118023, + XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB = 1000118030, + XR_TYPE_RENDER_MODEL_PATH_INFO_FB = 1000119000, + XR_TYPE_RENDER_MODEL_PROPERTIES_FB = 1000119001, + XR_TYPE_RENDER_MODEL_BUFFER_FB = 1000119002, + XR_TYPE_RENDER_MODEL_LOAD_INFO_FB = 1000119003, + XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB = 1000119004, + XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB = 1000119005, XR_TYPE_BINDING_MODIFICATIONS_KHR = 1000120000, + XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO = 1000121000, + XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO = 1000121001, + XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO = 1000121002, + XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO = 1000122000, + XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000, + XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001, + XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002, + XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000, + XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001, + XR_TYPE_SPACE_QUERY_INFO_FB = 1000156001, + XR_TYPE_SPACE_QUERY_RESULTS_FB = 1000156002, + XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB = 1000156003, + XR_TYPE_SPACE_UUID_FILTER_INFO_FB = 1000156054, + XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB = 1000156052, + XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB = 1000156103, + XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB = 1000156104, + XR_TYPE_SPACE_SAVE_INFO_FB = 1000158000, + XR_TYPE_SPACE_ERASE_INFO_FB = 1000158001, + XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB = 1000158106, + XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB = 1000158107, + XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB = 1000160000, + XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000, + XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000, + XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001, + XR_TYPE_SEMANTIC_LABELS_FB = 1000175000, + XR_TYPE_ROOM_LAYOUT_FB = 1000175001, + XR_TYPE_BOUNDARY_2D_FB = 1000175002, + XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000, + XR_TYPE_SPACE_CONTAINER_FB = 1000199000, + XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002, + XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB = 1000204000, + XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META = 1000227000, + XR_TYPE_PERFORMANCE_METRICS_STATE_META = 1000232001, + XR_TYPE_PERFORMANCE_METRICS_COUNTER_META = 1000232002, XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, @@ -359,6 +481,7 @@ typedef enum XrReferenceSpaceType { XR_REFERENCE_SPACE_TYPE_LOCAL = 2, XR_REFERENCE_SPACE_TYPE_STAGE = 3, XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000, + XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000, XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF } XrReferenceSpaceType; @@ -401,7 +524,17 @@ typedef enum XrObjectType { XR_OBJECT_TYPE_ACTION = 6, XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000019000, XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000, + XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT = 1000049000, XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000, + XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000, + XR_OBJECT_TYPE_SCENE_MSFT = 1000097001, + XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000, + XR_OBJECT_TYPE_FOVEATION_PROFILE_FB = 1000114000, + XR_OBJECT_TYPE_TRIANGLE_MESH_FB = 1000117000, + XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000, + XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002, + XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000, XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } XrObjectType; typedef XrFlags64 XrInstanceCreateFlags; @@ -443,6 +576,7 @@ static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT = 0x00000 static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT = 0x00000020; static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT = 0x00000040; static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND = 0x00000080; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR = 0x00000080; // alias of XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND typedef XrFlags64 XrCompositionLayerFlags; @@ -555,6 +689,7 @@ typedef struct XrVector3f { float z; } XrVector3f; +// XrSpaceVelocity extends XrSpaceLocation typedef struct XrSpaceVelocity { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1307,7 +1442,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( XrSession session, const XrHapticActionInfo* hapticActionInfo); -#endif +#endif /* !XR_NO_PROTOTYPES */ #define XR_KHR_composition_layer_cube 1 @@ -1327,8 +1462,9 @@ typedef struct XrCompositionLayerCubeKHR { #define XR_KHR_composition_layer_depth 1 -#define XR_KHR_composition_layer_depth_SPEC_VERSION 5 +#define XR_KHR_composition_layer_depth_SPEC_VERSION 6 #define XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME "XR_KHR_composition_layer_depth" +// XrCompositionLayerDepthInfoKHR extends XrCompositionLayerProjectionView typedef struct XrCompositionLayerDepthInfoKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1409,18 +1545,21 @@ typedef struct XrEventDataVisibilityMaskChangedKHR { typedef XrResult (XRAPI_PTR *PFN_xrGetVisibilityMaskKHR)(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR( XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_KHR_composition_layer_color_scale_bias 1 #define XR_KHR_composition_layer_color_scale_bias_SPEC_VERSION 5 #define XR_KHR_COMPOSITION_LAYER_COLOR_SCALE_BIAS_EXTENSION_NAME "XR_KHR_composition_layer_color_scale_bias" +// XrCompositionLayerColorScaleBiasKHR extends XrCompositionLayerBaseHeader typedef struct XrCompositionLayerColorScaleBiasKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1441,9 +1580,11 @@ typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR { typedef XrResult (XRAPI_PTR *PFN_xrInitializeLoaderKHR)(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR( const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_KHR_composition_layer_equirect2 1 @@ -1468,11 +1609,12 @@ typedef struct XrCompositionLayerEquirect2KHR { #define XR_KHR_binding_modification 1 #define XR_KHR_binding_modification_SPEC_VERSION 1 #define XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME "XR_KHR_binding_modification" -typedef struct XrBindingModificationBaseHeaderKHR { +typedef struct XR_MAY_ALIAS XrBindingModificationBaseHeaderKHR { XrStructureType type; const void* XR_MAY_ALIAS next; } XrBindingModificationBaseHeaderKHR; +// XrBindingModificationsKHR extends XrInteractionProfileSuggestedBinding typedef struct XrBindingModificationsKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1482,8 +1624,13 @@ typedef struct XrBindingModificationsKHR { +#define XR_KHR_swapchain_usage_input_attachment_bit 1 +#define XR_KHR_swapchain_usage_input_attachment_bit_SPEC_VERSION 3 +#define XR_KHR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_KHR_swapchain_usage_input_attachment_bit" + + #define XR_EXT_performance_settings 1 -#define XR_EXT_performance_settings_SPEC_VERSION 1 +#define XR_EXT_performance_settings_SPEC_VERSION 3 #define XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME "XR_EXT_performance_settings" typedef enum XrPerfSettingsDomainEXT { @@ -1525,31 +1672,35 @@ typedef struct XrEventDataPerfSettingsEXT { typedef XrResult (XRAPI_PTR *PFN_xrPerfSettingsSetPerformanceLevelEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT( XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_thermal_query 1 -#define XR_EXT_thermal_query_SPEC_VERSION 1 +#define XR_EXT_thermal_query_SPEC_VERSION 2 #define XR_EXT_THERMAL_QUERY_EXTENSION_NAME "XR_EXT_thermal_query" typedef XrResult (XRAPI_PTR *PFN_xrThermalGetTemperatureTrendEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT( XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_debug_utils 1 XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT) -#define XR_EXT_debug_utils_SPEC_VERSION 3 +#define XR_EXT_debug_utils_SPEC_VERSION 4 #define XR_EXT_DEBUG_UTILS_EXTENSION_NAME "XR_EXT_debug_utils" typedef XrFlags64 XrDebugUtilsMessageSeverityFlagsEXT; @@ -1600,6 +1751,7 @@ typedef XrBool32 (XRAPI_PTR *PFN_xrDebugUtilsMessengerCallbackEXT)( void* userData); +// XrDebugUtilsMessengerCreateInfoEXT extends XrInstanceCreateInfo typedef struct XrDebugUtilsMessengerCreateInfoEXT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1618,6 +1770,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrSessionEndDebugUtilsLabelRegionEXT)(XrSession typedef XrResult (XRAPI_PTR *PFN_xrSessionInsertDebugUtilsLabelEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT( XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo); @@ -1646,18 +1799,21 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT( XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT( XrSession session, const XrDebugUtilsLabelEXT* labelInfo); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_eye_gaze_interaction 1 -#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 1 +#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 2 #define XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME "XR_EXT_eye_gaze_interaction" +// XrSystemEyeGazeInteractionPropertiesEXT extends XrSystemProperties typedef struct XrSystemEyeGazeInteractionPropertiesEXT { XrStructureType type; void* XR_MAY_ALIAS next; XrBool32 supportsEyeGazeInteraction; } XrSystemEyeGazeInteractionPropertiesEXT; +// XrEyeGazeSampleTimeEXT extends XrSpaceLocation typedef struct XrEyeGazeSampleTimeEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1667,18 +1823,18 @@ typedef struct XrEyeGazeSampleTimeEXT { #define XR_EXTX_overlay 1 -#define XR_EXTX_overlay_SPEC_VERSION 4 +#define XR_EXTX_overlay_SPEC_VERSION 5 #define XR_EXTX_OVERLAY_EXTENSION_NAME "XR_EXTX_overlay" typedef XrFlags64 XrOverlaySessionCreateFlagsEXTX; // Flag bits for XrOverlaySessionCreateFlagsEXTX -static const XrOverlaySessionCreateFlagsEXTX XR_OVERLAY_SESSION_CREATE_RELAXED_DISPLAY_TIME_BIT_EXTX = 0x00000001; typedef XrFlags64 XrOverlayMainSessionFlagsEXTX; // Flag bits for XrOverlayMainSessionFlagsEXTX static const XrOverlayMainSessionFlagsEXTX XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX = 0x00000001; +// XrSessionCreateInfoOverlayEXTX extends XrSessionCreateInfo typedef struct XrSessionCreateInfoOverlayEXTX { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -1707,7 +1863,7 @@ typedef struct XrEventDataMainSessionVisibilityChangedEXTX { #define XR_MSFT_spatial_anchor 1 XR_DEFINE_HANDLE(XrSpatialAnchorMSFT) -#define XR_MSFT_spatial_anchor_SPEC_VERSION 1 +#define XR_MSFT_spatial_anchor_SPEC_VERSION 2 #define XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME "XR_MSFT_spatial_anchor" typedef struct XrSpatialAnchorCreateInfoMSFT { XrStructureType type; @@ -1729,6 +1885,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorSpaceMSFT)(XrSession sessi typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorMSFT)(XrSpatialAnchorMSFT anchor); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorMSFT( XrSession session, const XrSpatialAnchorCreateInfoMSFT* createInfo, @@ -1741,7 +1898,50 @@ XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorSpaceMSFT( XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( XrSpatialAnchorMSFT anchor); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_image_layout 1 +#define XR_FB_composition_layer_image_layout_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_IMAGE_LAYOUT_EXTENSION_NAME "XR_FB_composition_layer_image_layout" +typedef XrFlags64 XrCompositionLayerImageLayoutFlagsFB; + +// Flag bits for XrCompositionLayerImageLayoutFlagsFB +static const XrCompositionLayerImageLayoutFlagsFB XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB = 0x00000001; + +// XrCompositionLayerImageLayoutFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerImageLayoutFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrCompositionLayerImageLayoutFlagsFB flags; +} XrCompositionLayerImageLayoutFB; + + + +#define XR_FB_composition_layer_alpha_blend 1 +#define XR_FB_composition_layer_alpha_blend_SPEC_VERSION 2 +#define XR_FB_COMPOSITION_LAYER_ALPHA_BLEND_EXTENSION_NAME "XR_FB_composition_layer_alpha_blend" + +typedef enum XrBlendFactorFB { + XR_BLEND_FACTOR_ZERO_FB = 0, + XR_BLEND_FACTOR_ONE_FB = 1, + XR_BLEND_FACTOR_SRC_ALPHA_FB = 2, + XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB = 3, + XR_BLEND_FACTOR_DST_ALPHA_FB = 4, + XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB = 5, + XR_BLEND_FACTOR_MAX_ENUM_FB = 0x7FFFFFFF +} XrBlendFactorFB; +// XrCompositionLayerAlphaBlendFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerAlphaBlendFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBlendFactorFB srcFactorColor; + XrBlendFactorFB dstFactorColor; + XrBlendFactorFB srcFactorAlpha; + XrBlendFactorFB dstFactorAlpha; +} XrCompositionLayerAlphaBlendFB; + #define XR_MND_headless 1 @@ -1757,6 +1957,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( #define XR_EXT_view_configuration_depth_range 1 #define XR_EXT_view_configuration_depth_range_SPEC_VERSION 1 #define XR_EXT_VIEW_CONFIGURATION_DEPTH_RANGE_EXTENSION_NAME "XR_EXT_view_configuration_depth_range" +// XrViewConfigurationDepthRangeEXT extends XrViewConfigurationView typedef struct XrViewConfigurationDepthRangeEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1769,7 +1970,7 @@ typedef struct XrViewConfigurationDepthRangeEXT { #define XR_EXT_conformance_automation 1 -#define XR_EXT_conformance_automation_SPEC_VERSION 1 +#define XR_EXT_conformance_automation_SPEC_VERSION 3 #define XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME "XR_EXT_conformance_automation" typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceActiveEXT)(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive); typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateBoolEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state); @@ -1778,6 +1979,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateVector2fEXT)(XrSession ses typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceLocationEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceActiveEXT( XrSession session, XrPath interactionProfile, @@ -1808,12 +2010,15 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceLocationEXT( XrPath inputSourcePath, XrSpace space, XrPosef pose); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_spatial_graph_bridge 1 -#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 1 +XR_DEFINE_HANDLE(XrSpatialGraphNodeBindingMSFT) +#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 2 #define XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME "XR_MSFT_spatial_graph_bridge" +#define XR_GUID_SIZE_MSFT 16 typedef enum XrSpatialGraphNodeTypeMSFT { XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT = 1, @@ -1824,18 +2029,56 @@ typedef struct XrSpatialGraphNodeSpaceCreateInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; XrSpatialGraphNodeTypeMSFT nodeType; - uint8_t nodeId[16]; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; XrPosef pose; } XrSpatialGraphNodeSpaceCreateInfoMSFT; +typedef struct XrSpatialGraphStaticNodeBindingCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialGraphStaticNodeBindingCreateInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpatialGraphNodeBindingPropertiesGetInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; + XrPosef poseInNodeSpace; +} XrSpatialGraphNodeBindingPropertiesMSFT; + typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialGraphNodeSpaceMSFT)(XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrTryCreateSpatialGraphStaticNodeBindingMSFT)(XrSession session, const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, XrSpatialGraphNodeBindingMSFT* nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialGraphNodeBindingMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpatialGraphNodeBindingPropertiesMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding, const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, XrSpatialGraphNodeBindingPropertiesMSFT* properties); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); -#endif + +XRAPI_ATTR XrResult XRAPI_CALL xrTryCreateSpatialGraphStaticNodeBindingMSFT( + XrSession session, + const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, + XrSpatialGraphNodeBindingMSFT* nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialGraphNodeBindingMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpatialGraphNodeBindingPropertiesMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding, + const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, + XrSpatialGraphNodeBindingPropertiesMSFT* properties); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_hand_interaction 1 @@ -1848,7 +2091,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( #define XR_HAND_JOINT_COUNT_EXT 26 XR_DEFINE_HANDLE(XrHandTrackerEXT) -#define XR_EXT_hand_tracking_SPEC_VERSION 2 +#define XR_EXT_hand_tracking_SPEC_VERSION 4 #define XR_EXT_HAND_TRACKING_EXTENSION_NAME "XR_EXT_hand_tracking" typedef enum XrHandEXT { @@ -1889,8 +2132,10 @@ typedef enum XrHandJointEXT { typedef enum XrHandJointSetEXT { XR_HAND_JOINT_SET_DEFAULT_EXT = 0, + XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP = 1000149000, XR_HAND_JOINT_SET_MAX_ENUM_EXT = 0x7FFFFFFF } XrHandJointSetEXT; +// XrSystemHandTrackingPropertiesEXT extends XrSystemProperties typedef struct XrSystemHandTrackingPropertiesEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1931,6 +2176,7 @@ typedef struct XrHandJointLocationsEXT { XrHandJointLocationEXT* jointLocations; } XrHandJointLocationsEXT; +// XrHandJointVelocitiesEXT extends XrHandJointLocationsEXT typedef struct XrHandJointVelocitiesEXT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -1943,6 +2189,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrDestroyHandTrackerEXT)(XrHandTrackerEXT handT typedef XrResult (XRAPI_PTR *PFN_xrLocateHandJointsEXT)(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandTrackerEXT( XrSession session, const XrHandTrackerCreateInfoEXT* createInfo, @@ -1955,11 +2202,12 @@ XRAPI_ATTR XrResult XRAPI_CALL xrLocateHandJointsEXT( XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_hand_tracking_mesh 1 -#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 2 +#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 4 #define XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME "XR_MSFT_hand_tracking_mesh" typedef enum XrHandPoseTypeMSFT { @@ -1967,6 +2215,7 @@ typedef enum XrHandPoseTypeMSFT { XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT = 1, XR_HAND_POSE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF } XrHandPoseTypeMSFT; +// XrSystemHandTrackingMeshPropertiesMSFT extends XrSystemProperties typedef struct XrSystemHandTrackingMeshPropertiesMSFT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -2018,6 +2267,7 @@ typedef struct XrHandMeshMSFT { XrHandMeshVertexBufferMSFT vertexBuffer; } XrHandMeshMSFT; +// XrHandPoseTypeInfoMSFT extends XrHandTrackerCreateInfoEXT typedef struct XrHandPoseTypeInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2028,6 +2278,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateHandMeshSpaceMSFT)(XrHandTrackerEXT han typedef XrResult (XRAPI_PTR *PFN_xrUpdateHandMeshMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandMeshSpaceMSFT( XrHandTrackerEXT handTracker, const XrHandMeshSpaceCreateInfoMSFT* createInfo, @@ -2037,12 +2288,14 @@ XRAPI_ATTR XrResult XRAPI_CALL xrUpdateHandMeshMSFT( XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_MSFT_secondary_view_configuration 1 #define XR_MSFT_secondary_view_configuration_SPEC_VERSION 1 #define XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME "XR_MSFT_secondary_view_configuration" +// XrSecondaryViewConfigurationSessionBeginInfoMSFT extends XrSessionBeginInfo typedef struct XrSecondaryViewConfigurationSessionBeginInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2057,6 +2310,7 @@ typedef struct XrSecondaryViewConfigurationStateMSFT { XrBool32 active; } XrSecondaryViewConfigurationStateMSFT; +// XrSecondaryViewConfigurationFrameStateMSFT extends XrFrameState typedef struct XrSecondaryViewConfigurationFrameStateMSFT { XrStructureType type; void* XR_MAY_ALIAS next; @@ -2073,6 +2327,7 @@ typedef struct XrSecondaryViewConfigurationLayerInfoMSFT { const XrCompositionLayerBaseHeader* const* layers; } XrSecondaryViewConfigurationLayerInfoMSFT; +// XrSecondaryViewConfigurationFrameEndInfoMSFT extends XrFrameEndInfo typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2080,6 +2335,7 @@ typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { const XrSecondaryViewConfigurationLayerInfoMSFT* viewConfigurationLayersInfo; } XrSecondaryViewConfigurationFrameEndInfoMSFT; +// XrSecondaryViewConfigurationSwapchainCreateInfoMSFT extends XrSwapchainCreateInfo typedef struct XrSecondaryViewConfigurationSwapchainCreateInfoMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2142,6 +2398,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelPropertiesMSFT)(XrSession s typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelStateMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelKeyMSFT( XrSession session, XrPath topLevelUserPath, @@ -2163,7 +2420,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_EXT_win32_appcontainer_compatible 1 @@ -2174,6 +2432,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( #define XR_EPIC_view_configuration_fov 1 #define XR_EPIC_view_configuration_fov_SPEC_VERSION 2 #define XR_EPIC_VIEW_CONFIGURATION_FOV_EXTENSION_NAME "XR_EPIC_view_configuration_fov" +// XrViewConfigurationViewFovEPIC extends XrViewConfigurationView typedef struct XrViewConfigurationViewFovEPIC { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -2183,13 +2442,116 @@ typedef struct XrViewConfigurationViewFovEPIC { +#define XR_MSFT_composition_layer_reprojection 1 +#define XR_MSFT_composition_layer_reprojection_SPEC_VERSION 1 +#define XR_MSFT_COMPOSITION_LAYER_REPROJECTION_EXTENSION_NAME "XR_MSFT_composition_layer_reprojection" + +typedef enum XrReprojectionModeMSFT { + XR_REPROJECTION_MODE_DEPTH_MSFT = 1, + XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT = 2, + XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT = 3, + XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT = 4, + XR_REPROJECTION_MODE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrReprojectionModeMSFT; +// XrCompositionLayerReprojectionInfoMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReprojectionModeMSFT reprojectionMode; +} XrCompositionLayerReprojectionInfoMSFT; + +// XrCompositionLayerReprojectionPlaneOverrideMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionPlaneOverrideMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVector3f position; + XrVector3f normal; + XrVector3f velocity; +} XrCompositionLayerReprojectionPlaneOverrideMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReprojectionModesMSFT)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t modeCapacityInput, uint32_t* modeCountOutput, XrReprojectionModeMSFT* modes); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReprojectionModesMSFT( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t modeCapacityInput, + uint32_t* modeCountOutput, + XrReprojectionModeMSFT* modes); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_HUAWEI_controller_interaction 1 #define XR_HUAWEI_controller_interaction_SPEC_VERSION 1 #define XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HUAWEI_controller_interaction" +#define XR_FB_swapchain_update_state 1 +#define XR_FB_swapchain_update_state_SPEC_VERSION 3 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME "XR_FB_swapchain_update_state" +typedef struct XR_MAY_ALIAS XrSwapchainStateBaseHeaderFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainStateBaseHeaderFB; + +typedef XrResult (XRAPI_PTR *PFN_xrUpdateSwapchainFB)(XrSwapchain swapchain, const XrSwapchainStateBaseHeaderFB* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSwapchainStateFB)(XrSwapchain swapchain, XrSwapchainStateBaseHeaderFB* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateSwapchainFB( + XrSwapchain swapchain, + const XrSwapchainStateBaseHeaderFB* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSwapchainStateFB( + XrSwapchain swapchain, + XrSwapchainStateBaseHeaderFB* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_secure_content 1 +#define XR_FB_composition_layer_secure_content_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SECURE_CONTENT_EXTENSION_NAME "XR_FB_composition_layer_secure_content" +typedef XrFlags64 XrCompositionLayerSecureContentFlagsFB; + +// Flag bits for XrCompositionLayerSecureContentFlagsFB +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB = 0x00000001; +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB = 0x00000002; + +// XrCompositionLayerSecureContentFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSecureContentFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSecureContentFlagsFB flags; +} XrCompositionLayerSecureContentFB; + + + +#define XR_EXT_dpad_binding 1 +#define XR_EXT_dpad_binding_SPEC_VERSION 1 +#define XR_EXT_DPAD_BINDING_EXTENSION_NAME "XR_EXT_dpad_binding" +typedef struct XrInteractionProfileDpadBindingEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath binding; + XrActionSet actionSet; + float forceThreshold; + float forceThresholdReleased; + float centerRegion; + float wedgeAngle; + XrBool32 isSticky; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileDpadBindingEXT; + + + #define XR_VALVE_analog_threshold 1 -#define XR_VALVE_analog_threshold_SPEC_VERSION 1 +#define XR_VALVE_analog_threshold_SPEC_VERSION 2 #define XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME "XR_VALVE_analog_threshold" typedef struct XrInteractionProfileAnalogThresholdVALVE { XrStructureType type; @@ -2204,6 +2566,24 @@ typedef struct XrInteractionProfileAnalogThresholdVALVE { +#define XR_EXT_hand_joints_motion_range 1 +#define XR_EXT_hand_joints_motion_range_SPEC_VERSION 1 +#define XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME "XR_EXT_hand_joints_motion_range" + +typedef enum XrHandJointsMotionRangeEXT { + XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT = 1, + XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT = 2, + XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointsMotionRangeEXT; +// XrHandJointsMotionRangeInfoEXT extends XrHandJointsLocateInfoEXT +typedef struct XrHandJointsMotionRangeInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandJointsMotionRangeEXT handJointsMotionRange; +} XrHandJointsMotionRangeInfoEXT; + + + #define XR_EXT_samsung_odyssey_controller 1 #define XR_EXT_samsung_odyssey_controller_SPEC_VERSION 1 #define XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME "XR_EXT_samsung_odyssey_controller" @@ -2219,6 +2599,374 @@ typedef struct XrInteractionProfileAnalogThresholdVALVE { #define XR_MND_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_MND_swapchain_usage_input_attachment_bit" +#define XR_MSFT_scene_understanding 1 + + XR_DEFINE_HANDLE(XrSceneObserverMSFT) + + + XR_DEFINE_HANDLE(XrSceneMSFT) + +#define XR_MSFT_scene_understanding_SPEC_VERSION 1 +#define XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME "XR_MSFT_scene_understanding" + +typedef enum XrSceneComputeFeatureMSFT { + XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT = 1, + XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT = 2, + XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT = 1000098000, + XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeFeatureMSFT; + +typedef enum XrSceneComputeConsistencyMSFT { + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT = 1, + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT = 2, + XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT = 3, + XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeConsistencyMSFT; + +typedef enum XrMeshComputeLodMSFT { + XR_MESH_COMPUTE_LOD_COARSE_MSFT = 1, + XR_MESH_COMPUTE_LOD_MEDIUM_MSFT = 2, + XR_MESH_COMPUTE_LOD_FINE_MSFT = 3, + XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT = 4, + XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrMeshComputeLodMSFT; + +typedef enum XrSceneComponentTypeMSFT { + XR_SCENE_COMPONENT_TYPE_INVALID_MSFT = -1, + XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT = 1, + XR_SCENE_COMPONENT_TYPE_PLANE_MSFT = 2, + XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT = 1000098000, + XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComponentTypeMSFT; + +typedef enum XrSceneObjectTypeMSFT { + XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT = -1, + XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT = 1, + XR_SCENE_OBJECT_TYPE_WALL_MSFT = 2, + XR_SCENE_OBJECT_TYPE_FLOOR_MSFT = 3, + XR_SCENE_OBJECT_TYPE_CEILING_MSFT = 4, + XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT = 5, + XR_SCENE_OBJECT_TYPE_INFERRED_MSFT = 6, + XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneObjectTypeMSFT; + +typedef enum XrScenePlaneAlignmentTypeMSFT { + XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT = 0, + XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT = 1, + XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT = 2, + XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrScenePlaneAlignmentTypeMSFT; + +typedef enum XrSceneComputeStateMSFT { + XR_SCENE_COMPUTE_STATE_NONE_MSFT = 0, + XR_SCENE_COMPUTE_STATE_UPDATING_MSFT = 1, + XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT = 2, + XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT = 3, + XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeStateMSFT; +typedef struct XrUuidMSFT { + uint8_t bytes[16]; +} XrUuidMSFT; + +typedef struct XrSceneObserverCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneObserverCreateInfoMSFT; + +typedef struct XrSceneCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneCreateInfoMSFT; + +typedef struct XrSceneSphereBoundMSFT { + XrVector3f center; + float radius; +} XrSceneSphereBoundMSFT; + +typedef struct XrSceneOrientedBoxBoundMSFT { + XrPosef pose; + XrVector3f extents; +} XrSceneOrientedBoxBoundMSFT; + +typedef struct XrSceneFrustumBoundMSFT { + XrPosef pose; + XrFovf fov; + float farDistance; +} XrSceneFrustumBoundMSFT; + +typedef struct XrSceneBoundsMSFT { + XrSpace space; + XrTime time; + uint32_t sphereCount; + const XrSceneSphereBoundMSFT* spheres; + uint32_t boxCount; + const XrSceneOrientedBoxBoundMSFT* boxes; + uint32_t frustumCount; + const XrSceneFrustumBoundMSFT* frustums; +} XrSceneBoundsMSFT; + +typedef struct XrNewSceneComputeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestedFeatureCount; + const XrSceneComputeFeatureMSFT* requestedFeatures; + XrSceneComputeConsistencyMSFT consistency; + XrSceneBoundsMSFT bounds; +} XrNewSceneComputeInfoMSFT; + +// XrVisualMeshComputeLodInfoMSFT extends XrNewSceneComputeInfoMSFT +typedef struct XrVisualMeshComputeLodInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMeshComputeLodMSFT lod; +} XrVisualMeshComputeLodInfoMSFT; + +typedef struct XrSceneComponentMSFT { + XrSceneComponentTypeMSFT componentType; + XrUuidMSFT id; + XrUuidMSFT parentId; + XrTime updateTime; +} XrSceneComponentMSFT; + +typedef struct XrSceneComponentsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t componentCapacityInput; + uint32_t componentCountOutput; + XrSceneComponentMSFT* components; +} XrSceneComponentsMSFT; + +typedef struct XrSceneComponentsGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSceneComponentTypeMSFT componentType; +} XrSceneComponentsGetInfoMSFT; + +typedef struct XrSceneComponentLocationMSFT { + XrSpaceLocationFlags flags; + XrPosef pose; +} XrSceneComponentLocationMSFT; + +typedef struct XrSceneComponentLocationsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t locationCount; + XrSceneComponentLocationMSFT* locations; +} XrSceneComponentLocationsMSFT; + +typedef struct XrSceneComponentsLocateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + uint32_t componentIdCount; + const XrUuidMSFT* componentIds; +} XrSceneComponentsLocateInfoMSFT; + +typedef struct XrSceneObjectMSFT { + XrSceneObjectTypeMSFT objectType; +} XrSceneObjectMSFT; + +// XrSceneObjectsMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneObjectsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneObjectCount; + XrSceneObjectMSFT* sceneObjects; +} XrSceneObjectsMSFT; + +// XrSceneComponentParentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneComponentParentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT parentId; +} XrSceneComponentParentFilterInfoMSFT; + +// XrSceneObjectTypesFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneObjectTypesFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t objectTypeCount; + const XrSceneObjectTypeMSFT* objectTypes; +} XrSceneObjectTypesFilterInfoMSFT; + +typedef struct XrScenePlaneMSFT { + XrScenePlaneAlignmentTypeMSFT alignment; + XrExtent2Df size; + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrScenePlaneMSFT; + +// XrScenePlanesMSFT extends XrSceneComponentsMSFT +typedef struct XrScenePlanesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t scenePlaneCount; + XrScenePlaneMSFT* scenePlanes; +} XrScenePlanesMSFT; + +// XrScenePlaneAlignmentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrScenePlaneAlignmentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t alignmentCount; + const XrScenePlaneAlignmentTypeMSFT* alignments; +} XrScenePlaneAlignmentFilterInfoMSFT; + +typedef struct XrSceneMeshMSFT { + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrSceneMeshMSFT; + +// XrSceneMeshesMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneMeshesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneMeshCount; + XrSceneMeshMSFT* sceneMeshes; +} XrSceneMeshesMSFT; + +typedef struct XrSceneMeshBuffersGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t meshBufferId; +} XrSceneMeshBuffersGetInfoMSFT; + +typedef struct XrSceneMeshBuffersMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSceneMeshBuffersMSFT; + +typedef struct XrSceneMeshVertexBufferMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertices; +} XrSceneMeshVertexBufferMSFT; + +typedef struct XrSceneMeshIndicesUint32MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrSceneMeshIndicesUint32MSFT; + +typedef struct XrSceneMeshIndicesUint16MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint16_t* indices; +} XrSceneMeshIndicesUint16MSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSceneComputeFeaturesMSFT)(XrInstance instance, XrSystemId systemId, uint32_t featureCapacityInput, uint32_t* featureCountOutput, XrSceneComputeFeatureMSFT* features); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneObserverMSFT)(XrSession session, const XrSceneObserverCreateInfoMSFT* createInfo, XrSceneObserverMSFT* sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneObserverMSFT)(XrSceneObserverMSFT sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneCreateInfoMSFT* createInfo, XrSceneMSFT* scene); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneMSFT)(XrSceneMSFT scene); +typedef XrResult (XRAPI_PTR *PFN_xrComputeNewSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrNewSceneComputeInfoMSFT* computeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComputeStateMSFT)(XrSceneObserverMSFT sceneObserver, XrSceneComputeStateMSFT* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsGetInfoMSFT* getInfo, XrSceneComponentsMSFT* components); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsLocateInfoMSFT* locateInfo, XrSceneComponentLocationsMSFT* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneMeshBuffersMSFT)(XrSceneMSFT scene, const XrSceneMeshBuffersGetInfoMSFT* getInfo, XrSceneMeshBuffersMSFT* buffers); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSceneComputeFeaturesMSFT( + XrInstance instance, + XrSystemId systemId, + uint32_t featureCapacityInput, + uint32_t* featureCountOutput, + XrSceneComputeFeatureMSFT* features); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneObserverMSFT( + XrSession session, + const XrSceneObserverCreateInfoMSFT* createInfo, + XrSceneObserverMSFT* sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneObserverMSFT( + XrSceneObserverMSFT sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneCreateInfoMSFT* createInfo, + XrSceneMSFT* scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneMSFT( + XrSceneMSFT scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrComputeNewSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrNewSceneComputeInfoMSFT* computeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComputeStateMSFT( + XrSceneObserverMSFT sceneObserver, + XrSceneComputeStateMSFT* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsGetInfoMSFT* getInfo, + XrSceneComponentsMSFT* components); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsLocateInfoMSFT* locateInfo, + XrSceneComponentLocationsMSFT* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneMeshBuffersMSFT( + XrSceneMSFT scene, + const XrSceneMeshBuffersGetInfoMSFT* getInfo, + XrSceneMeshBuffersMSFT* buffers); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_scene_understanding_serialization 1 +#define XR_MSFT_scene_understanding_serialization_SPEC_VERSION 1 +#define XR_MSFT_SCENE_UNDERSTANDING_SERIALIZATION_EXTENSION_NAME "XR_MSFT_scene_understanding_serialization" +typedef struct XrSerializedSceneFragmentDataGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT sceneFragmentId; +} XrSerializedSceneFragmentDataGetInfoMSFT; + +typedef struct XrDeserializeSceneFragmentMSFT { + uint32_t bufferSize; + const uint8_t* buffer; +} XrDeserializeSceneFragmentMSFT; + +typedef struct XrSceneDeserializeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t fragmentCount; + const XrDeserializeSceneFragmentMSFT* fragments; +} XrSceneDeserializeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrDeserializeSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneDeserializeInfoMSFT* deserializeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSerializedSceneFragmentDataMSFT)(XrSceneMSFT scene, const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, uint32_t countInput, uint32_t* readOutput, uint8_t* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrDeserializeSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneDeserializeInfoMSFT* deserializeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSerializedSceneFragmentDataMSFT( + XrSceneMSFT scene, + const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, + uint32_t countInput, + uint32_t* readOutput, + uint8_t* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_FB_display_refresh_rate 1 #define XR_FB_display_refresh_rate_SPEC_VERSION 1 #define XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME "XR_FB_display_refresh_rate" @@ -2234,6 +2982,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrGetDisplayRefreshRateFB)(XrSession session, f typedef XrResult (XRAPI_PTR *PFN_xrRequestDisplayRefreshRateFB)(XrSession session, float displayRefreshRate); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateDisplayRefreshRatesFB( XrSession session, uint32_t displayRefreshRateCapacityInput, @@ -2247,7 +2996,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetDisplayRefreshRateFB( XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( XrSession session, float displayRefreshRate); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #define XR_HTC_vive_cosmos_controller_interaction 1 @@ -2255,8 +3005,171 @@ XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( #define XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_cosmos_controller_interaction" +#define XR_HTCX_vive_tracker_interaction 1 +#define XR_HTCX_vive_tracker_interaction_SPEC_VERSION 1 +#define XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTCX_vive_tracker_interaction" +typedef struct XrViveTrackerPathsHTCX { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath persistentPath; + XrPath rolePath; +} XrViveTrackerPathsHTCX; + +typedef struct XrEventDataViveTrackerConnectedHTCX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViveTrackerPathsHTCX* paths; +} XrEventDataViveTrackerConnectedHTCX; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViveTrackerPathsHTCX)(XrInstance instance, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrViveTrackerPathsHTCX* paths); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViveTrackerPathsHTCX( + XrInstance instance, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrViveTrackerPathsHTCX* paths); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_facial_tracking 1 + +#define XR_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 + + +#define XR_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 + +XR_DEFINE_HANDLE(XrFacialTrackerHTC) +#define XR_HTC_facial_tracking_SPEC_VERSION 1 +#define XR_HTC_FACIAL_TRACKING_EXTENSION_NAME "XR_HTC_facial_tracking" + +typedef enum XrEyeExpressionHTC { + XR_EYE_EXPRESSION_LEFT_BLINK_HTC = 0, + XR_EYE_EXPRESSION_LEFT_WIDE_HTC = 1, + XR_EYE_EXPRESSION_RIGHT_BLINK_HTC = 2, + XR_EYE_EXPRESSION_RIGHT_WIDE_HTC = 3, + XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC = 4, + XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC = 5, + XR_EYE_EXPRESSION_LEFT_DOWN_HTC = 6, + XR_EYE_EXPRESSION_RIGHT_DOWN_HTC = 7, + XR_EYE_EXPRESSION_LEFT_OUT_HTC = 8, + XR_EYE_EXPRESSION_RIGHT_IN_HTC = 9, + XR_EYE_EXPRESSION_LEFT_IN_HTC = 10, + XR_EYE_EXPRESSION_RIGHT_OUT_HTC = 11, + XR_EYE_EXPRESSION_LEFT_UP_HTC = 12, + XR_EYE_EXPRESSION_RIGHT_UP_HTC = 13, + XR_EYE_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrEyeExpressionHTC; + +typedef enum XrLipExpressionHTC { + XR_LIP_EXPRESSION_JAW_RIGHT_HTC = 0, + XR_LIP_EXPRESSION_JAW_LEFT_HTC = 1, + XR_LIP_EXPRESSION_JAW_FORWARD_HTC = 2, + XR_LIP_EXPRESSION_JAW_OPEN_HTC = 3, + XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC = 4, + XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC = 5, + XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC = 6, + XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC = 7, + XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC = 8, + XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC = 9, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC = 10, + XR_LIP_EXPRESSION_MOUTH_POUT_HTC = 11, + XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC = 12, + XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC = 13, + XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC = 14, + XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC = 15, + XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC = 16, + XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC = 17, + XR_LIP_EXPRESSION_CHEEK_SUCK_HTC = 18, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC = 19, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC = 20, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC = 21, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC = 22, + XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC = 23, + XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC = 24, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC = 25, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC = 26, + XR_LIP_EXPRESSION_TONGUE_LEFT_HTC = 27, + XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC = 28, + XR_LIP_EXPRESSION_TONGUE_UP_HTC = 29, + XR_LIP_EXPRESSION_TONGUE_DOWN_HTC = 30, + XR_LIP_EXPRESSION_TONGUE_ROLL_HTC = 31, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC = 32, + XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC = 33, + XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC = 34, + XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC = 35, + XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC = 36, + XR_LIP_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrLipExpressionHTC; + +typedef enum XrFacialTrackingTypeHTC { + XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC = 1, + XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC = 2, + XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFacialTrackingTypeHTC; +// XrSystemFacialTrackingPropertiesHTC extends XrSystemProperties +typedef struct XrSystemFacialTrackingPropertiesHTC { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportEyeFacialTracking; + XrBool32 supportLipFacialTracking; +} XrSystemFacialTrackingPropertiesHTC; + +typedef struct XrFacialExpressionsHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrTime sampleTime; + uint32_t expressionCount; + float* expressionWeightings; +} XrFacialExpressionsHTC; + +typedef struct XrFacialTrackerCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFacialTrackingTypeHTC facialTrackingType; +} XrFacialTrackerCreateInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFacialTrackerHTC)(XrSession session, const XrFacialTrackerCreateInfoHTC* createInfo, XrFacialTrackerHTC* facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFacialTrackerHTC)(XrFacialTrackerHTC facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFacialExpressionsHTC)(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC* facialExpressions); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFacialTrackerHTC( + XrSession session, + const XrFacialTrackerCreateInfoHTC* createInfo, + XrFacialTrackerHTC* facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFacialTrackerHTC( + XrFacialTrackerHTC facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFacialExpressionsHTC( + XrFacialTrackerHTC facialTracker, + XrFacialExpressionsHTC* facialExpressions); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_focus3_controller_interaction 1 +#define XR_HTC_vive_focus3_controller_interaction_SPEC_VERSION 2 +#define XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_focus3_controller_interaction" + + +#define XR_HTC_hand_interaction 1 +#define XR_HTC_hand_interaction_SPEC_VERSION 1 +#define XR_HTC_HAND_INTERACTION_EXTENSION_NAME "XR_HTC_hand_interaction" + + +#define XR_HTC_vive_wrist_tracker_interaction 1 +#define XR_HTC_vive_wrist_tracker_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_WRIST_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_wrist_tracker_interaction" + + #define XR_FB_color_space 1 -#define XR_FB_color_space_SPEC_VERSION 1 +#define XR_FB_color_space_SPEC_VERSION 2 #define XR_FB_COLOR_SPACE_EXTENSION_NAME "XR_FB_color_space" typedef enum XrColorSpaceFB { @@ -2270,6 +3183,7 @@ typedef enum XrColorSpaceFB { XR_COLOR_SPACE_ADOBE_RGB_FB = 7, XR_COLOR_SPACE_MAX_ENUM_FB = 0x7FFFFFFF } XrColorSpaceFB; +// XrSystemColorSpacePropertiesFB extends XrSystemProperties typedef struct XrSystemColorSpacePropertiesFB { XrStructureType type; void* XR_MAY_ALIAS next; @@ -2280,6 +3194,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrEnumerateColorSpacesFB)(XrSession session, ui typedef XrResult (XRAPI_PTR *PFN_xrSetColorSpaceFB)(XrSession session, const XrColorSpaceFB colorspace); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( XrSession session, uint32_t colorSpaceCapacityInput, @@ -2289,7 +3204,1354 @@ XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( XRAPI_ATTR XrResult XRAPI_CALL xrSetColorSpaceFB( XrSession session, const XrColorSpaceFB colorspace); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_mesh 1 +#define XR_FB_hand_tracking_mesh_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME "XR_FB_hand_tracking_mesh" +typedef struct XrVector4sFB { + int16_t x; + int16_t y; + int16_t z; + int16_t w; +} XrVector4sFB; + +typedef struct XrHandTrackingMeshFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCapacityInput; + uint32_t jointCountOutput; + XrPosef* jointBindPoses; + float* jointRadii; + XrHandJointEXT* jointParents; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertexPositions; + XrVector3f* vertexNormals; + XrVector2f* vertexUVs; + XrVector4sFB* vertexBlendIndices; + XrVector4f* vertexBlendWeights; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + int16_t* indices; +} XrHandTrackingMeshFB; + +// XrHandTrackingScaleFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingScaleFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + float sensorOutput; + float currentOutput; + XrBool32 overrideHandScale; + float overrideValueInput; +} XrHandTrackingScaleFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetHandMeshFB)(XrHandTrackerEXT handTracker, XrHandTrackingMeshFB* mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetHandMeshFB( + XrHandTrackerEXT handTracker, + XrHandTrackingMeshFB* mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_aim 1 +#define XR_FB_hand_tracking_aim_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME "XR_FB_hand_tracking_aim" +typedef XrFlags64 XrHandTrackingAimFlagsFB; + +// Flag bits for XrHandTrackingAimFlagsFB +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB = 0x00000001; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_VALID_BIT_FB = 0x00000002; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB = 0x00000004; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB = 0x00000008; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB = 0x00000010; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB = 0x00000020; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB = 0x00000040; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB = 0x00000080; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB = 0x00000100; + +// XrHandTrackingAimStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingAimStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandTrackingAimFlagsFB status; + XrPosef aimPose; + float pinchStrengthIndex; + float pinchStrengthMiddle; + float pinchStrengthRing; + float pinchStrengthLittle; +} XrHandTrackingAimStateFB; + + + +#define XR_FB_hand_tracking_capsules 1 +#define XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB 2 +#define XR_HAND_TRACKING_CAPSULE_COUNT_FB 19 +#define XR_FB_hand_tracking_capsules_SPEC_VERSION 3 +#define XR_FB_HAND_TRACKING_CAPSULES_EXTENSION_NAME "XR_FB_hand_tracking_capsules" +#define XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB +#define XR_FB_HAND_TRACKING_CAPSULE_COUNT XR_HAND_TRACKING_CAPSULE_COUNT_FB +typedef struct XrHandCapsuleFB { + XrVector3f points[XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB]; + float radius; + XrHandJointEXT joint; +} XrHandCapsuleFB; + +// XrHandTrackingCapsulesStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingCapsulesStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandCapsuleFB capsules[XR_HAND_TRACKING_CAPSULE_COUNT_FB]; +} XrHandTrackingCapsulesStateFB; + + + +#define XR_FB_spatial_entity 1 +XR_DEFINE_ATOM(XrAsyncRequestIdFB) +#define XR_UUID_SIZE_EXT 16 +#define XR_FB_spatial_entity_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_EXTENSION_NAME "XR_FB_spatial_entity" + +typedef enum XrSpaceComponentTypeFB { + XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB = 0, + XR_SPACE_COMPONENT_TYPE_STORABLE_FB = 1, + XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB = 3, + XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB = 4, + XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB = 5, + XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB = 6, + XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB = 7, + XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceComponentTypeFB; +// XrSystemSpatialEntityPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpatialEntityPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsSpatialEntity; +} XrSystemSpatialEntityPropertiesFB; + +typedef struct XrSpatialAnchorCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialAnchorCreateInfoFB; + +typedef struct XrSpaceComponentStatusSetInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; + XrDuration timeout; +} XrSpaceComponentStatusSetInfoFB; + +typedef struct XrSpaceComponentStatusFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 enabled; + XrBool32 changePending; +} XrSpaceComponentStatusFB; + +typedef struct XrUuidEXT { + uint8_t data[XR_UUID_SIZE_EXT]; +} XrUuidEXT; + +typedef struct XrEventDataSpatialAnchorCreateCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; +} XrEventDataSpatialAnchorCreateCompleteFB; + +typedef struct XrEventDataSpaceSetStatusCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; +} XrEventDataSpaceSetStatusCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFB)(XrSession session, const XrSpatialAnchorCreateInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceUuidFB)(XrSpace space, XrUuidEXT* uuid); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSpaceSupportedComponentsFB)(XrSpace space, uint32_t componentTypeCapacityInput, uint32_t* componentTypeCountOutput, XrSpaceComponentTypeFB* componentTypes); +typedef XrResult (XRAPI_PTR *PFN_xrSetSpaceComponentStatusFB)(XrSpace space, const XrSpaceComponentStatusSetInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceComponentStatusFB)(XrSpace space, XrSpaceComponentTypeFB componentType, XrSpaceComponentStatusFB* status); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFB( + XrSession session, + const XrSpatialAnchorCreateInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceUuidFB( + XrSpace space, + XrUuidEXT* uuid); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSpaceSupportedComponentsFB( + XrSpace space, + uint32_t componentTypeCapacityInput, + uint32_t* componentTypeCountOutput, + XrSpaceComponentTypeFB* componentTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetSpaceComponentStatusFB( + XrSpace space, + const XrSpaceComponentStatusSetInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceComponentStatusFB( + XrSpace space, + XrSpaceComponentTypeFB componentType, + XrSpaceComponentStatusFB* status); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation 1 +XR_DEFINE_HANDLE(XrFoveationProfileFB) +#define XR_FB_foveation_SPEC_VERSION 1 +#define XR_FB_FOVEATION_EXTENSION_NAME "XR_FB_foveation" +typedef XrFlags64 XrSwapchainCreateFoveationFlagsFB; + +// Flag bits for XrSwapchainCreateFoveationFlagsFB +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB = 0x00000001; +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB = 0x00000002; + +typedef XrFlags64 XrSwapchainStateFoveationFlagsFB; + +// Flag bits for XrSwapchainStateFoveationFlagsFB + +typedef struct XrFoveationProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrFoveationProfileCreateInfoFB; + +// XrSwapchainCreateInfoFoveationFB extends XrSwapchainCreateInfo +typedef struct XrSwapchainCreateInfoFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainCreateFoveationFlagsFB flags; +} XrSwapchainCreateInfoFoveationFB; + +typedef struct XrSwapchainStateFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainStateFoveationFlagsFB flags; + XrFoveationProfileFB profile; +} XrSwapchainStateFoveationFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFoveationProfileFB)(XrSession session, const XrFoveationProfileCreateInfoFB* createInfo, XrFoveationProfileFB* profile); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFoveationProfileFB)(XrFoveationProfileFB profile); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFoveationProfileFB( + XrSession session, + const XrFoveationProfileCreateInfoFB* createInfo, + XrFoveationProfileFB* profile); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFoveationProfileFB( + XrFoveationProfileFB profile); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation_configuration 1 +#define XR_FB_foveation_configuration_SPEC_VERSION 1 +#define XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME "XR_FB_foveation_configuration" + +typedef enum XrFoveationLevelFB { + XR_FOVEATION_LEVEL_NONE_FB = 0, + XR_FOVEATION_LEVEL_LOW_FB = 1, + XR_FOVEATION_LEVEL_MEDIUM_FB = 2, + XR_FOVEATION_LEVEL_HIGH_FB = 3, + XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationLevelFB; + +typedef enum XrFoveationDynamicFB { + XR_FOVEATION_DYNAMIC_DISABLED_FB = 0, + XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB = 1, + XR_FOVEATION_DYNAMIC_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationDynamicFB; +// XrFoveationLevelProfileCreateInfoFB extends XrFoveationProfileCreateInfoFB +typedef struct XrFoveationLevelProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrFoveationLevelFB level; + float verticalOffset; + XrFoveationDynamicFB dynamic; +} XrFoveationLevelProfileCreateInfoFB; + + + +#define XR_FB_keyboard_tracking 1 +#define XR_FB_keyboard_tracking_SPEC_VERSION 1 +#define XR_FB_KEYBOARD_TRACKING_EXTENSION_NAME "XR_FB_keyboard_tracking" +#define XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB 128 +typedef XrFlags64 XrKeyboardTrackingFlagsFB; + +// Flag bits for XrKeyboardTrackingFlagsFB +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_EXISTS_BIT_FB = 0x00000001; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_REMOTE_BIT_FB = 0x00000004; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB = 0x00000008; + +typedef XrFlags64 XrKeyboardTrackingQueryFlagsFB; + +// Flag bits for XrKeyboardTrackingQueryFlagsFB +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB = 0x00000004; + +// XrSystemKeyboardTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemKeyboardTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsKeyboardTracking; +} XrSystemKeyboardTrackingPropertiesFB; + +typedef struct XrKeyboardTrackingDescriptionFB { + uint64_t trackedKeyboardId; + XrVector3f size; + XrKeyboardTrackingFlagsFB flags; + char name[XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB]; +} XrKeyboardTrackingDescriptionFB; + +typedef struct XrKeyboardSpaceCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint64_t trackedKeyboardId; +} XrKeyboardSpaceCreateInfoFB; + +typedef struct XrKeyboardTrackingQueryFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrKeyboardTrackingQueryFlagsFB flags; +} XrKeyboardTrackingQueryFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySystemTrackedKeyboardFB)(XrSession session, const XrKeyboardTrackingQueryFB* queryInfo, XrKeyboardTrackingDescriptionFB* keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrCreateKeyboardSpaceFB)(XrSession session, const XrKeyboardSpaceCreateInfoFB* createInfo, XrSpace* keyboardSpace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySystemTrackedKeyboardFB( + XrSession session, + const XrKeyboardTrackingQueryFB* queryInfo, + XrKeyboardTrackingDescriptionFB* keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateKeyboardSpaceFB( + XrSession session, + const XrKeyboardSpaceCreateInfoFB* createInfo, + XrSpace* keyboardSpace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_triangle_mesh 1 +XR_DEFINE_HANDLE(XrTriangleMeshFB) +#define XR_FB_triangle_mesh_SPEC_VERSION 2 +#define XR_FB_TRIANGLE_MESH_EXTENSION_NAME "XR_FB_triangle_mesh" + +typedef enum XrWindingOrderFB { + XR_WINDING_ORDER_UNKNOWN_FB = 0, + XR_WINDING_ORDER_CW_FB = 1, + XR_WINDING_ORDER_CCW_FB = 2, + XR_WINDING_ORDER_MAX_ENUM_FB = 0x7FFFFFFF +} XrWindingOrderFB; +typedef XrFlags64 XrTriangleMeshFlagsFB; + +// Flag bits for XrTriangleMeshFlagsFB +static const XrTriangleMeshFlagsFB XR_TRIANGLE_MESH_MUTABLE_BIT_FB = 0x00000001; + +typedef struct XrTriangleMeshCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTriangleMeshFlagsFB flags; + XrWindingOrderFB windingOrder; + uint32_t vertexCount; + const XrVector3f* vertexBuffer; + uint32_t triangleCount; + const uint32_t* indexBuffer; +} XrTriangleMeshCreateInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateTriangleMeshFB)(XrSession session, const XrTriangleMeshCreateInfoFB* createInfo, XrTriangleMeshFB* outTriangleMesh); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyTriangleMeshFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetVertexBufferFB)(XrTriangleMeshFB mesh, XrVector3f** outVertexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetIndexBufferFB)(XrTriangleMeshFB mesh, uint32_t** outIndexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginUpdateFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndUpdateFB)(XrTriangleMeshFB mesh, uint32_t vertexCount, uint32_t triangleCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginVertexBufferUpdateFB)(XrTriangleMeshFB mesh, uint32_t* outVertexCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndVertexBufferUpdateFB)(XrTriangleMeshFB mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateTriangleMeshFB( + XrSession session, + const XrTriangleMeshCreateInfoFB* createInfo, + XrTriangleMeshFB* outTriangleMesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyTriangleMeshFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetVertexBufferFB( + XrTriangleMeshFB mesh, + XrVector3f** outVertexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetIndexBufferFB( + XrTriangleMeshFB mesh, + uint32_t** outIndexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginUpdateFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndUpdateFB( + XrTriangleMeshFB mesh, + uint32_t vertexCount, + uint32_t triangleCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginVertexBufferUpdateFB( + XrTriangleMeshFB mesh, + uint32_t* outVertexCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndVertexBufferUpdateFB( + XrTriangleMeshFB mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough 1 +XR_DEFINE_HANDLE(XrPassthroughFB) +XR_DEFINE_HANDLE(XrPassthroughLayerFB) +XR_DEFINE_HANDLE(XrGeometryInstanceFB) +#define XR_FB_passthrough_SPEC_VERSION 2 +#define XR_FB_PASSTHROUGH_EXTENSION_NAME "XR_FB_passthrough" +#define XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB 256 + +typedef enum XrPassthroughLayerPurposeFB { + XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB = 0, + XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB = 1, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB = 1000203001, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB = 1000203002, + XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB = 0x7FFFFFFF +} XrPassthroughLayerPurposeFB; +typedef XrFlags64 XrPassthroughFlagsFB; + +// Flag bits for XrPassthroughFlagsFB +static const XrPassthroughFlagsFB XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001; + +typedef XrFlags64 XrPassthroughStateChangedFlagsFB; + +// Flag bits for XrPassthroughStateChangedFlagsFB +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB = 0x00000001; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB = 0x00000002; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB = 0x00000004; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB = 0x00000008; + +// XrSystemPassthroughPropertiesFB extends XrSystemProperties +typedef struct XrSystemPassthroughPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsPassthrough; +} XrSystemPassthroughPropertiesFB; + +typedef struct XrPassthroughCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFlagsFB flags; +} XrPassthroughCreateInfoFB; + +typedef struct XrPassthroughLayerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFB passthrough; + XrPassthroughFlagsFB flags; + XrPassthroughLayerPurposeFB purpose; +} XrPassthroughLayerCreateInfoFB; + +// XrCompositionLayerPassthroughFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerPassthroughFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags flags; + XrSpace space; + XrPassthroughLayerFB layerHandle; +} XrCompositionLayerPassthroughFB; + +typedef struct XrGeometryInstanceCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughLayerFB layer; + XrTriangleMeshFB mesh; + XrSpace baseSpace; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceCreateInfoFB; + +typedef struct XrGeometryInstanceTransformFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceTransformFB; + +typedef struct XrPassthroughStyleFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float textureOpacityFactor; + XrColor4f edgeColor; +} XrPassthroughStyleFB; + +// XrPassthroughColorMapMonoToRgbaFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToRgbaFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToRgbaFB; + +// XrPassthroughColorMapMonoToMonoFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToMonoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToMonoFB; + +// XrPassthroughBrightnessContrastSaturationFB extends XrPassthroughStyleFB +typedef struct XrPassthroughBrightnessContrastSaturationFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float brightness; + float contrast; + float saturation; +} XrPassthroughBrightnessContrastSaturationFB; + +typedef struct XrEventDataPassthroughStateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughStateChangedFlagsFB flags; +} XrEventDataPassthroughStateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughFB)(XrSession session, const XrPassthroughCreateInfoFB* createInfo, XrPassthroughFB* outPassthrough); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughStartFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughPauseFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughLayerFB)(XrSession session, const XrPassthroughLayerCreateInfoFB* createInfo, XrPassthroughLayerFB* outLayer); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughLayerFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerPauseFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerResumeFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetStyleFB)(XrPassthroughLayerFB layer, const XrPassthroughStyleFB* style); +typedef XrResult (XRAPI_PTR *PFN_xrCreateGeometryInstanceFB)(XrSession session, const XrGeometryInstanceCreateInfoFB* createInfo, XrGeometryInstanceFB* outGeometryInstance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyGeometryInstanceFB)(XrGeometryInstanceFB instance); +typedef XrResult (XRAPI_PTR *PFN_xrGeometryInstanceSetTransformFB)(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB* transformation); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughFB( + XrSession session, + const XrPassthroughCreateInfoFB* createInfo, + XrPassthroughFB* outPassthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughStartFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughPauseFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughLayerFB( + XrSession session, + const XrPassthroughLayerCreateInfoFB* createInfo, + XrPassthroughLayerFB* outLayer); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughLayerFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerPauseFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerResumeFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetStyleFB( + XrPassthroughLayerFB layer, + const XrPassthroughStyleFB* style); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateGeometryInstanceFB( + XrSession session, + const XrGeometryInstanceCreateInfoFB* createInfo, + XrGeometryInstanceFB* outGeometryInstance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyGeometryInstanceFB( + XrGeometryInstanceFB instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB( + XrGeometryInstanceFB instance, + const XrGeometryInstanceTransformFB* transformation); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_render_model 1 + +#define XR_NULL_RENDER_MODEL_KEY_FB 0 + +XR_DEFINE_ATOM(XrRenderModelKeyFB) +#define XR_FB_render_model_SPEC_VERSION 2 +#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model" +#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB 64 +typedef XrFlags64 XrRenderModelFlagsFB; + +// Flag bits for XrRenderModelFlagsFB +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB = 0x00000001; +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB = 0x00000002; + +typedef struct XrRenderModelPathInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath path; +} XrRenderModelPathInfoFB; + +typedef struct XrRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vendorId; + char modelName[XR_MAX_RENDER_MODEL_NAME_SIZE_FB]; + XrRenderModelKeyFB modelKey; + uint32_t modelVersion; + XrRenderModelFlagsFB flags; +} XrRenderModelPropertiesFB; + +typedef struct XrRenderModelBufferFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + uint8_t* buffer; +} XrRenderModelBufferFB; + +typedef struct XrRenderModelLoadInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelKeyFB modelKey; +} XrRenderModelLoadInfoFB; + +// XrSystemRenderModelPropertiesFB extends XrSystemProperties +typedef struct XrSystemRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsRenderModelLoading; +} XrSystemRenderModelPropertiesFB; + +// XrRenderModelCapabilitiesRequestFB extends XrSystemProperties +typedef struct XrRenderModelCapabilitiesRequestFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelFlagsFB flags; +} XrRenderModelCapabilitiesRequestFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateRenderModelPathsFB)(XrSession session, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrRenderModelPathInfoFB* paths); +typedef XrResult (XRAPI_PTR *PFN_xrGetRenderModelPropertiesFB)(XrSession session, XrPath path, XrRenderModelPropertiesFB* properties); +typedef XrResult (XRAPI_PTR *PFN_xrLoadRenderModelFB)(XrSession session, const XrRenderModelLoadInfoFB* info, XrRenderModelBufferFB* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateRenderModelPathsFB( + XrSession session, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrRenderModelPathInfoFB* paths); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetRenderModelPropertiesFB( + XrSession session, + XrPath path, + XrRenderModelPropertiesFB* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB( + XrSession session, + const XrRenderModelLoadInfoFB* info, + XrRenderModelBufferFB* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_foveated_rendering 1 +#define XR_VARJO_foveated_rendering_SPEC_VERSION 2 +#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering" +// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo +typedef struct XrViewLocateFoveatedRenderingVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrViewLocateFoveatedRenderingVARJO; + +// XrFoveatedViewConfigurationViewVARJO extends XrViewConfigurationView +typedef struct XrFoveatedViewConfigurationViewVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrFoveatedViewConfigurationViewVARJO; + +// XrSystemFoveatedRenderingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemFoveatedRenderingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFoveatedRendering; +} XrSystemFoveatedRenderingPropertiesVARJO; + + + +#define XR_VARJO_composition_layer_depth_test 1 +#define XR_VARJO_composition_layer_depth_test_SPEC_VERSION 2 +#define XR_VARJO_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_VARJO_composition_layer_depth_test" +// XrCompositionLayerDepthTestVARJO extends XrCompositionLayerProjection +typedef struct XrCompositionLayerDepthTestVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float depthTestRangeNearZ; + float depthTestRangeFarZ; +} XrCompositionLayerDepthTestVARJO; + + + +#define XR_VARJO_environment_depth_estimation 1 +#define XR_VARJO_environment_depth_estimation_SPEC_VERSION 1 +#define XR_VARJO_ENVIRONMENT_DEPTH_ESTIMATION_EXTENSION_NAME "XR_VARJO_environment_depth_estimation" +typedef XrResult (XRAPI_PTR *PFN_xrSetEnvironmentDepthEstimationVARJO)(XrSession session, XrBool32 enabled); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetEnvironmentDepthEstimationVARJO( + XrSession session, + XrBool32 enabled); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_marker_tracking 1 +#define XR_VARJO_marker_tracking_SPEC_VERSION 1 +#define XR_VARJO_MARKER_TRACKING_EXTENSION_NAME "XR_VARJO_marker_tracking" +// XrSystemMarkerTrackingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemMarkerTrackingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsMarkerTracking; +} XrSystemMarkerTrackingPropertiesVARJO; + +typedef struct XrEventDataMarkerTrackingUpdateVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrBool32 isActive; + XrBool32 isPredicted; + XrTime time; +} XrEventDataMarkerTrackingUpdateVARJO; + +typedef struct XrMarkerSpaceCreateInfoVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrPosef poseInMarkerSpace; +} XrMarkerSpaceCreateInfoVARJO; + +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingVARJO)(XrSession session, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingTimeoutVARJO)(XrSession session, uint64_t markerId, XrDuration timeout); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingPredictionVARJO)(XrSession session, uint64_t markerId, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerSizeVARJO)(XrSession session, uint64_t markerId, XrExtent2Df* size); +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceVARJO)(XrSession session, const XrMarkerSpaceCreateInfoVARJO* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingVARJO( + XrSession session, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingTimeoutVARJO( + XrSession session, + uint64_t markerId, + XrDuration timeout); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingPredictionVARJO( + XrSession session, + uint64_t markerId, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerSizeVARJO( + XrSession session, + uint64_t markerId, + XrExtent2Df* size); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceVARJO( + XrSession session, + const XrMarkerSpaceCreateInfoVARJO* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_view_offset 1 +#define XR_VARJO_view_offset_SPEC_VERSION 1 +#define XR_VARJO_VIEW_OFFSET_EXTENSION_NAME "XR_VARJO_view_offset" +typedef XrResult (XRAPI_PTR *PFN_xrSetViewOffsetVARJO)(XrSession session, float offset); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetViewOffsetVARJO( + XrSession session, + float offset); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_spatial_anchor_persistence 1 +XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT) +#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256 +#define XR_MSFT_spatial_anchor_persistence_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_PERSISTENCE_EXTENSION_NAME "XR_MSFT_spatial_anchor_persistence" +typedef struct XrSpatialAnchorPersistenceNameMSFT { + char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT]; +} XrSpatialAnchorPersistenceNameMSFT; + +typedef struct XrSpatialAnchorPersistenceInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; + XrSpatialAnchorMSFT spatialAnchor; +} XrSpatialAnchorPersistenceInfoMSFT; + +typedef struct XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; +} XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorStoreConnectionMSFT)(XrSession session, XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorStoreConnectionMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrPersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, uint32_t spatialAnchorNamesCapacityInput, uint32_t* spatialAnchorNamesCountOutput, XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPersistedNameMSFT)(XrSession session, const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, XrSpatialAnchorMSFT* spatialAnchor); +typedef XrResult (XRAPI_PTR *PFN_xrUnpersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); +typedef XrResult (XRAPI_PTR *PFN_xrClearSpatialAnchorStoreMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorStoreConnectionMSFT( + XrSession session, + XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorStoreConnectionMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrPersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePersistedSpatialAnchorNamesMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + uint32_t spatialAnchorNamesCapacityInput, + uint32_t* spatialAnchorNamesCountOutput, + XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPersistedNameMSFT( + XrSession session, + const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, + XrSpatialAnchorMSFT* spatialAnchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrUnpersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); + +XRAPI_ATTR XrResult XRAPI_CALL xrClearSpatialAnchorStoreMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ULTRALEAP_hand_tracking_forearm 1 + +#define XR_HAND_FOREARM_JOINT_COUNT_ULTRALEAP 27 + +#define XR_ULTRALEAP_hand_tracking_forearm_SPEC_VERSION 1 +#define XR_ULTRALEAP_HAND_TRACKING_FOREARM_EXTENSION_NAME "XR_ULTRALEAP_hand_tracking_forearm" + +typedef enum XrHandForearmJointULTRALEAP { + XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP = 0, + XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP = 1, + XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP = 2, + XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP = 3, + XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP = 4, + XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP = 5, + XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP = 6, + XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP = 7, + XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP = 8, + XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP = 9, + XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP = 10, + XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP = 11, + XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP = 12, + XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP = 13, + XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP = 14, + XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP = 15, + XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP = 16, + XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP = 17, + XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP = 18, + XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP = 19, + XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP = 20, + XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP = 21, + XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP = 22, + XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP = 23, + XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP = 24, + XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP = 25, + XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP = 26, + XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP = 0x7FFFFFFF +} XrHandForearmJointULTRALEAP; + + +#define XR_FB_spatial_entity_query 1 +#define XR_FB_spatial_entity_query_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_QUERY_EXTENSION_NAME "XR_FB_spatial_entity_query" + +typedef enum XrSpaceQueryActionFB { + XR_SPACE_QUERY_ACTION_LOAD_FB = 0, + XR_SPACE_QUERY_ACTION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceQueryActionFB; + +typedef enum XrSpaceStorageLocationFB { + XR_SPACE_STORAGE_LOCATION_INVALID_FB = 0, + XR_SPACE_STORAGE_LOCATION_LOCAL_FB = 1, + XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceStorageLocationFB; +typedef struct XR_MAY_ALIAS XrSpaceQueryInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceQueryInfoBaseHeaderFB; + +typedef struct XR_MAY_ALIAS XrSpaceFilterInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceFilterInfoBaseHeaderFB; + +typedef struct XrSpaceQueryInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceQueryActionFB queryAction; + uint32_t maxResultCount; + XrDuration timeout; + const XrSpaceFilterInfoBaseHeaderFB* filter; + const XrSpaceFilterInfoBaseHeaderFB* excludeFilter; +} XrSpaceQueryInfoFB; + +// XrSpaceStorageLocationFilterInfoFB extends XrSpaceFilterInfoBaseHeaderFB +typedef struct XrSpaceStorageLocationFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceStorageLocationFB location; +} XrSpaceStorageLocationFilterInfoFB; + +typedef struct XrSpaceUuidFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCount; + XrUuidEXT* uuids; +} XrSpaceUuidFilterInfoFB; + +typedef struct XrSpaceComponentFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; +} XrSpaceComponentFilterInfoFB; + +typedef struct XrSpaceQueryResultFB { + XrSpace space; + XrUuidEXT uuid; +} XrSpaceQueryResultFB; + +typedef struct XrSpaceQueryResultsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t resultCapacityInput; + uint32_t resultCountOutput; + XrSpaceQueryResultFB* results; +} XrSpaceQueryResultsFB; + +typedef struct XrEventDataSpaceQueryResultsAvailableFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; +} XrEventDataSpaceQueryResultsAvailableFB; + +typedef struct XrEventDataSpaceQueryCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSpaceQueryCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySpacesFB)(XrSession session, const XrSpaceQueryInfoBaseHeaderFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrRetrieveSpaceQueryResultsFB)(XrSession session, XrAsyncRequestIdFB requestId, XrSpaceQueryResultsFB* results); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySpacesFB( + XrSession session, + const XrSpaceQueryInfoBaseHeaderFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrRetrieveSpaceQueryResultsFB( + XrSession session, + XrAsyncRequestIdFB requestId, + XrSpaceQueryResultsFB* results); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_storage 1 +#define XR_FB_spatial_entity_storage_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_STORAGE_EXTENSION_NAME "XR_FB_spatial_entity_storage" + +typedef enum XrSpacePersistenceModeFB { + XR_SPACE_PERSISTENCE_MODE_INVALID_FB = 0, + XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB = 1, + XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpacePersistenceModeFB; +typedef struct XrSpaceSaveInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; + XrSpacePersistenceModeFB persistenceMode; +} XrSpaceSaveInfoFB; + +typedef struct XrSpaceEraseInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; +} XrSpaceEraseInfoFB; + +typedef struct XrEventDataSpaceSaveCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceSaveCompleteFB; + +typedef struct XrEventDataSpaceEraseCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceEraseCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrSaveSpaceFB)(XrSession session, const XrSpaceSaveInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrEraseSpaceFB)(XrSession session, const XrSpaceEraseInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSaveSpaceFB( + XrSession session, + const XrSpaceSaveInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrEraseSpaceFB( + XrSession session, + const XrSpaceEraseInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_space_warp 1 +#define XR_FB_space_warp_SPEC_VERSION 2 +#define XR_FB_SPACE_WARP_EXTENSION_NAME "XR_FB_space_warp" +typedef XrFlags64 XrCompositionLayerSpaceWarpInfoFlagsFB; + +// Flag bits for XrCompositionLayerSpaceWarpInfoFlagsFB +static const XrCompositionLayerSpaceWarpInfoFlagsFB XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB = 0x00000001; + +// XrCompositionLayerSpaceWarpInfoFB extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerSpaceWarpInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSpaceWarpInfoFlagsFB layerFlags; + XrSwapchainSubImage motionVectorSubImage; + XrPosef appSpaceDeltaPose; + XrSwapchainSubImage depthSubImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerSpaceWarpInfoFB; + +// XrSystemSpaceWarpPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpaceWarpPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedMotionVectorImageRectWidth; + uint32_t recommendedMotionVectorImageRectHeight; +} XrSystemSpaceWarpPropertiesFB; + + + +#define XR_FB_scene 1 +#define XR_FB_scene_SPEC_VERSION 1 +#define XR_FB_SCENE_EXTENSION_NAME "XR_FB_scene" +typedef struct XrExtent3DfFB { + float width; + float height; + float depth; +} XrExtent3DfFB; + +typedef struct XrOffset3DfFB { + float x; + float y; + float z; +} XrOffset3DfFB; + +typedef struct XrRect3DfFB { + XrOffset3DfFB offset; + XrExtent3DfFB extent; +} XrRect3DfFB; + +typedef struct XrSemanticLabelsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + char* buffer; +} XrSemanticLabelsFB; + +typedef struct XrRoomLayoutFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidEXT floorUuid; + XrUuidEXT ceilingUuid; + uint32_t wallUuidCapacityInput; + uint32_t wallUuidCountOutput; + XrUuidEXT* wallUuids; +} XrRoomLayoutFB; + +typedef struct XrBoundary2DFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; +} XrBoundary2DFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox2DFB)(XrSession session, XrSpace space, XrRect2Df* boundingBox2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox3DFB)(XrSession session, XrSpace space, XrRect3DfFB* boundingBox3DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceSemanticLabelsFB)(XrSession session, XrSpace space, XrSemanticLabelsFB* semanticLabelsOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundary2DFB)(XrSession session, XrSpace space, XrBoundary2DFB* boundary2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceRoomLayoutFB)(XrSession session, XrSpace space, XrRoomLayoutFB* roomLayoutOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox2DFB( + XrSession session, + XrSpace space, + XrRect2Df* boundingBox2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox3DFB( + XrSession session, + XrSpace space, + XrRect3DfFB* boundingBox3DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceSemanticLabelsFB( + XrSession session, + XrSpace space, + XrSemanticLabelsFB* semanticLabelsOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundary2DFB( + XrSession session, + XrSpace space, + XrBoundary2DFB* boundary2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceRoomLayoutFB( + XrSession session, + XrSpace space, + XrRoomLayoutFB* roomLayoutOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_palm_pose 1 +#define XR_EXT_palm_pose_SPEC_VERSION 2 +#define XR_EXT_PALM_POSE_EXTENSION_NAME "XR_EXT_palm_pose" + + +#define XR_ALMALENCE_digital_lens_control 1 +#define XR_ALMALENCE_digital_lens_control_SPEC_VERSION 1 +#define XR_ALMALENCE_DIGITAL_LENS_CONTROL_EXTENSION_NAME "XR_ALMALENCE_digital_lens_control" +typedef XrFlags64 XrDigitalLensControlFlagsALMALENCE; + +// Flag bits for XrDigitalLensControlFlagsALMALENCE +static const XrDigitalLensControlFlagsALMALENCE XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE = 0x00000001; + +typedef struct XrDigitalLensControlALMALENCE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDigitalLensControlFlagsALMALENCE flags; +} XrDigitalLensControlALMALENCE; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDigitalLensControlALMALENCE)(XrSession session, const XrDigitalLensControlALMALENCE* digitalLensControl); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE( + XrSession session, + const XrDigitalLensControlALMALENCE* digitalLensControl); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_container 1 +#define XR_FB_spatial_entity_container_SPEC_VERSION 2 +#define XR_FB_SPATIAL_ENTITY_CONTAINER_EXTENSION_NAME "XR_FB_spatial_entity_container" +typedef struct XrSpaceContainerFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCapacityInput; + uint32_t uuidCountOutput; + XrUuidEXT* uuids; +} XrSpaceContainerFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceContainerFB)(XrSession session, XrSpace space, XrSpaceContainerFB* spaceContainerOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceContainerFB( + XrSession session, + XrSpace space, + XrSpaceContainerFB* spaceContainerOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough_keyboard_hands 1 +#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 2 +#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands" +typedef struct XrPassthroughKeyboardHandsIntensityFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float leftHandIntensity; + float rightHandIntensity; +} XrPassthroughKeyboardHandsIntensityFB; + +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB)(XrPassthroughLayerFB layer, const XrPassthroughKeyboardHandsIntensityFB* intensity); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetKeyboardHandsIntensityFB( + XrPassthroughLayerFB layer, + const XrPassthroughKeyboardHandsIntensityFB* intensity); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_settings 1 +#define XR_FB_composition_layer_settings_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SETTINGS_EXTENSION_NAME "XR_FB_composition_layer_settings" +typedef XrFlags64 XrCompositionLayerSettingsFlagsFB; + +// Flag bits for XrCompositionLayerSettingsFlagsFB +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB = 0x00000001; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB = 0x00000002; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB = 0x00000004; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB = 0x00000008; + +// XrCompositionLayerSettingsFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSettingsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSettingsFlagsFB layerFlags; +} XrCompositionLayerSettingsFB; + + + +#define XR_META_performance_metrics 1 +#define XR_META_performance_metrics_SPEC_VERSION 1 +#define XR_META_PERFORMANCE_METRICS_EXTENSION_NAME "XR_META_performance_metrics" + +typedef enum XrPerformanceMetricsCounterUnitMETA { + XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META = 0, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META = 1, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META = 2, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META = 3, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META = 4, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META = 0x7FFFFFFF +} XrPerformanceMetricsCounterUnitMETA; +typedef XrFlags64 XrPerformanceMetricsCounterFlagsMETA; + +// Flag bits for XrPerformanceMetricsCounterFlagsMETA +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META = 0x00000001; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META = 0x00000002; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META = 0x00000004; + +typedef struct XrPerformanceMetricsStateMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 enabled; +} XrPerformanceMetricsStateMETA; + +typedef struct XrPerformanceMetricsCounterMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerformanceMetricsCounterFlagsMETA counterFlags; + XrPerformanceMetricsCounterUnitMETA counterUnit; + uint32_t uintValue; + float floatValue; +} XrPerformanceMetricsCounterMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePerformanceMetricsCounterPathsMETA)(XrInstance instance, uint32_t counterPathCapacityInput, uint32_t* counterPathCountOutput, XrPath* counterPaths); +typedef XrResult (XRAPI_PTR *PFN_xrSetPerformanceMetricsStateMETA)(XrSession session, const XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetPerformanceMetricsStateMETA)(XrSession session, XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrQueryPerformanceMetricsCounterMETA)(XrSession session, XrPath counterPath, XrPerformanceMetricsCounterMETA* counter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePerformanceMetricsCounterPathsMETA( + XrInstance instance, + uint32_t counterPathCapacityInput, + uint32_t* counterPathCountOutput, + XrPath* counterPaths); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetPerformanceMetricsStateMETA( + XrSession session, + const XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPerformanceMetricsStateMETA( + XrSession session, + XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrQueryPerformanceMetricsCounterMETA( + XrSession session, + XrPath counterPath, + XrPerformanceMetricsCounterMETA* counter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_uuid 1 +#define XR_EXT_uuid_SPEC_VERSION 1 +#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" #ifdef __cplusplus } diff --git a/ext/openxr/openxr_platform.h b/ext/openxr/openxr_platform.h index f7e6338064..f0fbf6955a 100644 --- a/ext/openxr/openxr_platform.h +++ b/ext/openxr/openxr_platform.h @@ -2,7 +2,7 @@ #define OPENXR_PLATFORM_H_ 1 /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -35,11 +35,13 @@ typedef enum XrAndroidThreadTypeKHR { typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_ANDROID */ #ifdef XR_USE_PLATFORM_ANDROID @@ -50,12 +52,14 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_ANDROID */ #ifdef XR_USE_PLATFORM_ANDROID @@ -63,6 +67,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( #define XR_KHR_android_create_instance 1 #define XR_KHR_android_create_instance_SPEC_VERSION 3 #define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance" +// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo typedef struct XrInstanceCreateInfoAndroidKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -75,7 +80,7 @@ typedef struct XrInstanceCreateInfoAndroidKHR { #ifdef XR_USE_GRAPHICS_API_VULKAN #define XR_KHR_vulkan_swapchain_format_list 1 -#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 3 +#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4 #define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list" typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { XrStructureType type; @@ -89,9 +94,10 @@ typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { #ifdef XR_USE_GRAPHICS_API_OPENGL #define XR_KHR_opengl_enable 1 -#define XR_KHR_opengl_enable_SPEC_VERSION 9 +#define XR_KHR_opengl_enable_SPEC_VERSION 10 #define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable" #ifdef XR_USE_PLATFORM_WIN32 +// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLWin32KHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -101,6 +107,7 @@ typedef struct XrGraphicsBindingOpenGLWin32KHR { #endif // XR_USE_PLATFORM_WIN32 #ifdef XR_USE_PLATFORM_XLIB +// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLXlibKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -113,6 +120,7 @@ typedef struct XrGraphicsBindingOpenGLXlibKHR { #endif // XR_USE_PLATFORM_XLIB #ifdef XR_USE_PLATFORM_XCB +// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLXcbKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -126,6 +134,7 @@ typedef struct XrGraphicsBindingOpenGLXcbKHR { #endif // XR_USE_PLATFORM_XCB #ifdef XR_USE_PLATFORM_WAYLAND +// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLWaylandKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -149,19 +158,22 @@ typedef struct XrGraphicsRequirementsOpenGLKHR { typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_OPENGL */ #ifdef XR_USE_GRAPHICS_API_OPENGL_ES #define XR_KHR_opengl_es_enable 1 -#define XR_KHR_opengl_es_enable_SPEC_VERSION 7 +#define XR_KHR_opengl_es_enable_SPEC_VERSION 8 #define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable" #ifdef XR_USE_PLATFORM_ANDROID +// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingOpenGLESAndroidKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -187,18 +199,21 @@ typedef struct XrGraphicsRequirementsOpenGLESKHR { typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ #ifdef XR_USE_GRAPHICS_API_VULKAN #define XR_KHR_vulkan_enable 1 -#define XR_KHR_vulkan_enable_SPEC_VERSION 7 +#define XR_KHR_vulkan_enable_SPEC_VERSION 8 #define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable" +// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingVulkanKHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -228,6 +243,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instan typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR( XrInstance instance, XrSystemId systemId, @@ -252,14 +268,16 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_VULKAN */ #ifdef XR_USE_GRAPHICS_API_D3D11 #define XR_KHR_D3D11_enable 1 -#define XR_KHR_D3D11_enable_SPEC_VERSION 5 +#define XR_KHR_D3D11_enable_SPEC_VERSION 9 #define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable" +// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingD3D11KHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -282,18 +300,21 @@ typedef struct XrGraphicsRequirementsD3D11KHR { typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_D3D11 */ #ifdef XR_USE_GRAPHICS_API_D3D12 #define XR_KHR_D3D12_enable 1 -#define XR_KHR_D3D12_enable_SPEC_VERSION 7 +#define XR_KHR_D3D12_enable_SPEC_VERSION 9 #define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable" +// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo typedef struct XrGraphicsBindingD3D12KHR { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -317,11 +338,13 @@ typedef struct XrGraphicsRequirementsD3D12KHR { typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_D3D12 */ #ifdef XR_USE_PLATFORM_WIN32 @@ -333,6 +356,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrIn typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR( XrInstance instance, const LARGE_INTEGER* performanceCounter, @@ -342,7 +366,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR( XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_WIN32 */ #ifdef XR_USE_TIMESPEC @@ -354,6 +379,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance inst typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR( XrInstance instance, const struct timespec* timespecTime, @@ -363,7 +389,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR( XrInstance instance, XrTime time, struct timespec* timespecTime); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_TIMESPEC */ #ifdef XR_USE_PLATFORM_ANDROID @@ -383,7 +410,7 @@ typedef struct XrLoaderInitInfoAndroidKHR { #ifdef XR_USE_GRAPHICS_API_VULKAN #define XR_KHR_vulkan_enable2 1 -#define XR_KHR_vulkan_enable2_SPEC_VERSION 1 +#define XR_KHR_vulkan_enable2_SPEC_VERSION 2 #define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2" typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR; @@ -427,12 +454,13 @@ typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR; typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR; -typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR*createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult); typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice); typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR( XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, @@ -454,7 +482,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_GRAPHICS_API_VULKAN */ #ifdef XR_USE_PLATFORM_EGL @@ -462,6 +491,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( #define XR_MNDX_egl_enable 1 #define XR_MNDX_egl_enable_SPEC_VERSION 1 #define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable" +// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo typedef struct XrGraphicsBindingEGLMNDX { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -482,6 +512,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)( typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); #ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT( XrSession session, IUnknown* perceptionAnchor, @@ -491,7 +522,8 @@ XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); -#endif +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ #endif /* XR_USE_PLATFORM_WIN32 */ #ifdef XR_USE_PLATFORM_WIN32 @@ -500,6 +532,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( #define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1 #define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment" #ifdef XR_USE_PLATFORM_WIN32 +// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo typedef struct XrHolographicWindowAttachmentMSFT { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -522,6 +555,7 @@ static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCH static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002; #ifdef XR_USE_PLATFORM_ANDROID +// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { XrStructureType type; const void* XR_MAY_ALIAS next; @@ -531,6 +565,124 @@ typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { #endif /* XR_USE_PLATFORM_ANDROID */ +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_OCULUS_audio_device_guid 1 +#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1 +#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid" +#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128 +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_foveation_vulkan 1 +#define XR_FB_foveation_vulkan_SPEC_VERSION 1 +#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan" +// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR +typedef struct XrSwapchainImageFoveationVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; + uint32_t width; + uint32_t height; +} XrSwapchainImageFoveationVulkanFB; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_swapchain_update_state_android_surface 1 +#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface" +#ifdef XR_USE_PLATFORM_ANDROID +typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t width; + uint32_t height; +} XrSwapchainStateAndroidSurfaceDimensionsFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_FB_swapchain_update_state_opengl_es 1 +#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es" +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +typedef struct XrSwapchainStateSamplerOpenGLESFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + EGLenum minFilter; + EGLenum magFilter; + EGLenum wrapModeS; + EGLenum wrapModeT; + EGLenum swizzleRed; + EGLenum swizzleGreen; + EGLenum swizzleBlue; + EGLenum swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerOpenGLESFB; +#endif // XR_USE_GRAPHICS_API_OPENGL_ES + +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_swapchain_update_state_vulkan 1 +#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan" +#ifdef XR_USE_GRAPHICS_API_VULKAN +typedef struct XrSwapchainStateSamplerVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkFilter minFilter; + VkFilter magFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode wrapModeS; + VkSamplerAddressMode wrapModeT; + VkComponentSwizzle swizzleRed; + VkComponentSwizzle swizzleGreen; + VkComponentSwizzle swizzleBlue; + VkComponentSwizzle swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerVulkanFB; +#endif // XR_USE_GRAPHICS_API_VULKAN + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_META_vulkan_swapchain_create_info 1 +#define XR_META_vulkan_swapchain_create_info_SPEC_VERSION 1 +#define XR_META_VULKAN_SWAPCHAIN_CREATE_INFO_EXTENSION_NAME "XR_META_vulkan_swapchain_create_info" +// XrVulkanSwapchainCreateInfoMETA extends XrSwapchainCreateInfo +typedef struct XrVulkanSwapchainCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkImageCreateFlags additionalCreateFlags; + VkImageUsageFlags additionalUsageFlags; +} XrVulkanSwapchainCreateInfoMETA; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + #ifdef __cplusplus } #endif diff --git a/ext/openxr/openxr_platform_defines.h b/ext/openxr/openxr_platform_defines.h index a7ffcb459e..31fa05a0c8 100644 --- a/ext/openxr/openxr_platform_defines.h +++ b/ext/openxr/openxr_platform_defines.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ diff --git a/ext/openxr/openxr_reflection.h b/ext/openxr/openxr_reflection.h index 5597c94a6e..31e2e40945 100644 --- a/ext/openxr/openxr_reflection.h +++ b/ext/openxr/openxr_reflection.h @@ -2,7 +2,7 @@ #define OPENXR_REFLECTION_H_ 1 /* -** Copyright (c) 2017-2021, The Khronos Group Inc. +** Copyright (c) 2017-2022, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -85,13 +85,37 @@ XR_ENUM_STR(XrResult); _(XR_ERROR_LOCALIZED_NAME_DUPLICATED, -48) \ _(XR_ERROR_LOCALIZED_NAME_INVALID, -49) \ _(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, -50) \ + _(XR_ERROR_RUNTIME_UNAVAILABLE, -51) \ _(XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR, -1000003000) \ _(XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR, -1000003001) \ _(XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT, -1000039001) \ _(XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT, -1000053000) \ _(XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT, -1000055000) \ + _(XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT, -1000066000) \ + _(XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT, -1000097000) \ + _(XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT, -1000097001) \ + _(XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT, -1000097002) \ + _(XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT, -1000097003) \ + _(XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT, -1000097004) \ + _(XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT, -1000097005) \ _(XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB, -1000101000) \ _(XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB, -1000108000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB, -1000113000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB, -1000113001) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB, -1000113002) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB, -1000113003) \ + _(XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB, -1000118000) \ + _(XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB, -1000118001) \ + _(XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB, -1000118002) \ + _(XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB, -1000118003) \ + _(XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB, -1000118004) \ + _(XR_ERROR_UNKNOWN_PASSTHROUGH_FB, -1000118050) \ + _(XR_ERROR_RENDER_MODEL_KEY_INVALID_FB, -1000119000) \ + _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \ + _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \ + _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \ _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrStructureType(_) \ @@ -183,9 +207,14 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR, 1000034000) \ _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT, 1000039000) \ _(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT, 1000039001) \ + _(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB, 1000040000) \ + _(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB, 1000041001) \ _(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT, 1000046000) \ _(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, 1000048004) \ _(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT, 1000049000) \ + _(XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT, 1000049001) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT, 1000049002) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT, 1000049003) \ _(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, 1000051000) \ _(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, 1000051001) \ _(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, 1000051002) \ @@ -209,16 +238,118 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \ _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \ _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT, 1000066000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \ _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \ + _(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \ + _(XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT, 1000078000) \ _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \ + _(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \ _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \ _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \ _(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, 1000090001) \ _(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, 1000090003) \ _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, 1000091000) \ + _(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT, 1000097000) \ + _(XR_TYPE_SCENE_CREATE_INFO_MSFT, 1000097001) \ + _(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT, 1000097002) \ + _(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT, 1000097003) \ + _(XR_TYPE_SCENE_COMPONENTS_MSFT, 1000097004) \ + _(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT, 1000097005) \ + _(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT, 1000097006) \ + _(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT, 1000097007) \ + _(XR_TYPE_SCENE_OBJECTS_MSFT, 1000097008) \ + _(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT, 1000097009) \ + _(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT, 1000097010) \ + _(XR_TYPE_SCENE_PLANES_MSFT, 1000097011) \ + _(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT, 1000097012) \ + _(XR_TYPE_SCENE_MESHES_MSFT, 1000097013) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT, 1000097014) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_MSFT, 1000097015) \ + _(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT, 1000097016) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT, 1000097017) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT, 1000097018) \ + _(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT, 1000098000) \ + _(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT, 1000098001) \ _(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB, 1000101000) \ + _(XR_TYPE_VIVE_TRACKER_PATHS_HTCX, 1000103000) \ + _(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX, 1000103001) \ + _(XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC, 1000104000) \ + _(XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC, 1000104001) \ + _(XR_TYPE_FACIAL_EXPRESSIONS_HTC, 1000104002) \ _(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB, 1000108000) \ + _(XR_TYPE_HAND_TRACKING_MESH_FB, 1000110001) \ + _(XR_TYPE_HAND_TRACKING_SCALE_FB, 1000110003) \ + _(XR_TYPE_HAND_TRACKING_AIM_STATE_FB, 1000111001) \ + _(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB, 1000112000) \ + _(XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB, 1000113004) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB, 1000113003) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB, 1000113007) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_FB, 1000113001) \ + _(XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB, 1000113005) \ + _(XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB, 1000113006) \ + _(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB, 1000114000) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB, 1000114001) \ + _(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB, 1000114002) \ + _(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB, 1000115000) \ + _(XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB, 1000116009) \ + _(XR_TYPE_KEYBOARD_TRACKING_QUERY_FB, 1000116004) \ + _(XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB, 1000116002) \ + _(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB, 1000117001) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB, 1000118000) \ + _(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, 1000118001) \ + _(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, 1000118002) \ + _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, 1000118003) \ + _(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB, 1000118004) \ + _(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB, 1000118005) \ + _(XR_TYPE_PASSTHROUGH_STYLE_FB, 1000118020) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB, 1000118021) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB, 1000118022) \ + _(XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB, 1000118023) \ + _(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB, 1000118030) \ + _(XR_TYPE_RENDER_MODEL_PATH_INFO_FB, 1000119000) \ + _(XR_TYPE_RENDER_MODEL_PROPERTIES_FB, 1000119001) \ + _(XR_TYPE_RENDER_MODEL_BUFFER_FB, 1000119002) \ + _(XR_TYPE_RENDER_MODEL_LOAD_INFO_FB, 1000119003) \ + _(XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB, 1000119004) \ + _(XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB, 1000119005) \ _(XR_TYPE_BINDING_MODIFICATIONS_KHR, 1000120000) \ + _(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO, 1000121000) \ + _(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO, 1000121001) \ + _(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO, 1000121002) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO, 1000122000) \ + _(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \ + _(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \ + _(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \ + _(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \ + _(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \ + _(XR_TYPE_SPACE_QUERY_INFO_FB, 1000156001) \ + _(XR_TYPE_SPACE_QUERY_RESULTS_FB, 1000156002) \ + _(XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, 1000156003) \ + _(XR_TYPE_SPACE_UUID_FILTER_INFO_FB, 1000156054) \ + _(XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB, 1000156052) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB, 1000156103) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB, 1000156104) \ + _(XR_TYPE_SPACE_SAVE_INFO_FB, 1000158000) \ + _(XR_TYPE_SPACE_ERASE_INFO_FB, 1000158001) \ + _(XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB, 1000158106) \ + _(XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB, 1000158107) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB, 1000160000) \ + _(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \ + _(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \ + _(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \ + _(XR_TYPE_SEMANTIC_LABELS_FB, 1000175000) \ + _(XR_TYPE_ROOM_LAYOUT_FB, 1000175001) \ + _(XR_TYPE_BOUNDARY_2D_FB, 1000175002) \ + _(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \ + _(XR_TYPE_SPACE_CONTAINER_FB, 1000199000) \ + _(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \ + _(XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB, 1000204000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META, 1000227000) \ + _(XR_TYPE_PERFORMANCE_METRICS_STATE_META, 1000232001) \ + _(XR_TYPE_PERFORMANCE_METRICS_COUNTER_META, 1000232002) \ _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrFormFactor(_) \ @@ -244,6 +375,7 @@ XR_ENUM_STR(XrResult); _(XR_REFERENCE_SPACE_TYPE_LOCAL, 2) \ _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \ _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \ + _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \ _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrActionType(_) \ @@ -282,7 +414,17 @@ XR_ENUM_STR(XrResult); _(XR_OBJECT_TYPE_ACTION, 6) \ _(XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, 1000019000) \ _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \ + _(XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT, 1000049000) \ _(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \ + _(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \ + _(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \ + _(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \ + _(XR_OBJECT_TYPE_FOVEATION_PROFILE_FB, 1000114000) \ + _(XR_OBJECT_TYPE_TRIANGLE_MESH_FB, 1000117000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \ + _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \ _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \ @@ -322,6 +464,15 @@ XR_ENUM_STR(XrResult); _(XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT, 75) \ _(XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrBlendFactorFB(_) \ + _(XR_BLEND_FACTOR_ZERO_FB, 0) \ + _(XR_BLEND_FACTOR_ONE_FB, 1) \ + _(XR_BLEND_FACTOR_SRC_ALPHA_FB, 2) \ + _(XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB, 3) \ + _(XR_BLEND_FACTOR_DST_ALPHA_FB, 4) \ + _(XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB, 5) \ + _(XR_BLEND_FACTOR_MAX_ENUM_FB, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrSpatialGraphNodeTypeMSFT(_) \ _(XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT, 1) \ _(XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT, 2) \ @@ -363,6 +514,7 @@ XR_ENUM_STR(XrResult); #define XR_LIST_ENUM_XrHandJointSetEXT(_) \ _(XR_HAND_JOINT_SET_DEFAULT_EXT, 0) \ + _(XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP, 1000149000) \ _(XR_HAND_JOINT_SET_MAX_ENUM_EXT, 0x7FFFFFFF) #define XR_LIST_ENUM_XrHandPoseTypeMSFT(_) \ @@ -370,6 +522,133 @@ XR_ENUM_STR(XrResult); _(XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT, 1) \ _(XR_HAND_POSE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrReprojectionModeMSFT(_) \ + _(XR_REPROJECTION_MODE_DEPTH_MSFT, 1) \ + _(XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT, 2) \ + _(XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT, 3) \ + _(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \ + _(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \ + _(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \ + _(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \ + _(XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeFeatureMSFT(_) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT, 2) \ + _(XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT, 1000098000) \ + _(XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeConsistencyMSFT(_) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT, 2) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT, 3) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMeshComputeLodMSFT(_) \ + _(XR_MESH_COMPUTE_LOD_COARSE_MSFT, 1) \ + _(XR_MESH_COMPUTE_LOD_MEDIUM_MSFT, 2) \ + _(XR_MESH_COMPUTE_LOD_FINE_MSFT, 3) \ + _(XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT, 4) \ + _(XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComponentTypeMSFT(_) \ + _(XR_SCENE_COMPONENT_TYPE_INVALID_MSFT, -1) \ + _(XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT, 1) \ + _(XR_SCENE_COMPONENT_TYPE_PLANE_MSFT, 2) \ + _(XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT, 1000098000) \ + _(XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneObjectTypeMSFT(_) \ + _(XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT, -1) \ + _(XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, 1) \ + _(XR_SCENE_OBJECT_TYPE_WALL_MSFT, 2) \ + _(XR_SCENE_OBJECT_TYPE_FLOOR_MSFT, 3) \ + _(XR_SCENE_OBJECT_TYPE_CEILING_MSFT, 4) \ + _(XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT, 5) \ + _(XR_SCENE_OBJECT_TYPE_INFERRED_MSFT, 6) \ + _(XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrScenePlaneAlignmentTypeMSFT(_) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT, 0) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT, 1) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT, 2) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeStateMSFT(_) \ + _(XR_SCENE_COMPUTE_STATE_NONE_MSFT, 0) \ + _(XR_SCENE_COMPUTE_STATE_UPDATING_MSFT, 1) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT, 2) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT, 3) \ + _(XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeExpressionHTC(_) \ + _(XR_EYE_EXPRESSION_LEFT_BLINK_HTC, 0) \ + _(XR_EYE_EXPRESSION_LEFT_WIDE_HTC, 1) \ + _(XR_EYE_EXPRESSION_RIGHT_BLINK_HTC, 2) \ + _(XR_EYE_EXPRESSION_RIGHT_WIDE_HTC, 3) \ + _(XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC, 4) \ + _(XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC, 5) \ + _(XR_EYE_EXPRESSION_LEFT_DOWN_HTC, 6) \ + _(XR_EYE_EXPRESSION_RIGHT_DOWN_HTC, 7) \ + _(XR_EYE_EXPRESSION_LEFT_OUT_HTC, 8) \ + _(XR_EYE_EXPRESSION_RIGHT_IN_HTC, 9) \ + _(XR_EYE_EXPRESSION_LEFT_IN_HTC, 10) \ + _(XR_EYE_EXPRESSION_RIGHT_OUT_HTC, 11) \ + _(XR_EYE_EXPRESSION_LEFT_UP_HTC, 12) \ + _(XR_EYE_EXPRESSION_RIGHT_UP_HTC, 13) \ + _(XR_EYE_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLipExpressionHTC(_) \ + _(XR_LIP_EXPRESSION_JAW_RIGHT_HTC, 0) \ + _(XR_LIP_EXPRESSION_JAW_LEFT_HTC, 1) \ + _(XR_LIP_EXPRESSION_JAW_FORWARD_HTC, 2) \ + _(XR_LIP_EXPRESSION_JAW_OPEN_HTC, 3) \ + _(XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC, 4) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC, 5) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC, 6) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC, 7) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC, 8) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC, 9) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC, 10) \ + _(XR_LIP_EXPRESSION_MOUTH_POUT_HTC, 11) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC, 12) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC, 13) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC, 14) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC, 15) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC, 16) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC, 17) \ + _(XR_LIP_EXPRESSION_CHEEK_SUCK_HTC, 18) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC, 19) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC, 20) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC, 21) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC, 22) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC, 23) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC, 24) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC, 25) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC, 26) \ + _(XR_LIP_EXPRESSION_TONGUE_LEFT_HTC, 27) \ + _(XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC, 28) \ + _(XR_LIP_EXPRESSION_TONGUE_UP_HTC, 29) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWN_HTC, 30) \ + _(XR_LIP_EXPRESSION_TONGUE_ROLL_HTC, 31) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC, 32) \ + _(XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC, 33) \ + _(XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC, 34) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC, 35) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC, 36) \ + _(XR_LIP_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFacialTrackingTypeHTC(_) \ + _(XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC, 1) \ + _(XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC, 2) \ + _(XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrColorSpaceFB(_) \ _(XR_COLOR_SPACE_UNMANAGED_FB, 0) \ _(XR_COLOR_SPACE_REC2020_FB, 1) \ @@ -381,6 +660,93 @@ XR_ENUM_STR(XrResult); _(XR_COLOR_SPACE_ADOBE_RGB_FB, 7) \ _(XR_COLOR_SPACE_MAX_ENUM_FB, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrSpaceComponentTypeFB(_) \ + _(XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB, 0) \ + _(XR_SPACE_COMPONENT_TYPE_STORABLE_FB, 1) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB, 3) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB, 4) \ + _(XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB, 5) \ + _(XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB, 6) \ + _(XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB, 7) \ + _(XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationLevelFB(_) \ + _(XR_FOVEATION_LEVEL_NONE_FB, 0) \ + _(XR_FOVEATION_LEVEL_LOW_FB, 1) \ + _(XR_FOVEATION_LEVEL_MEDIUM_FB, 2) \ + _(XR_FOVEATION_LEVEL_HIGH_FB, 3) \ + _(XR_FOVEATION_LEVEL_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationDynamicFB(_) \ + _(XR_FOVEATION_DYNAMIC_DISABLED_FB, 0) \ + _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB, 1) \ + _(XR_FOVEATION_DYNAMIC_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrWindingOrderFB(_) \ + _(XR_WINDING_ORDER_UNKNOWN_FB, 0) \ + _(XR_WINDING_ORDER_CW_FB, 1) \ + _(XR_WINDING_ORDER_CCW_FB, 2) \ + _(XR_WINDING_ORDER_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughLayerPurposeFB(_) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, 0) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB, 1) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB, 1000203001) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB, 1000203002) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandForearmJointULTRALEAP(_) \ + _(XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP, 0) \ + _(XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP, 1) \ + _(XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP, 2) \ + _(XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP, 3) \ + _(XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP, 4) \ + _(XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP, 5) \ + _(XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP, 6) \ + _(XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP, 7) \ + _(XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP, 8) \ + _(XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP, 9) \ + _(XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP, 10) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP, 11) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP, 12) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP, 13) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP, 14) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP, 15) \ + _(XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP, 16) \ + _(XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP, 17) \ + _(XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP, 18) \ + _(XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP, 19) \ + _(XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP, 20) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP, 21) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP, 22) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP, 23) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP, 24) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP, 25) \ + _(XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP, 26) \ + _(XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceQueryActionFB(_) \ + _(XR_SPACE_QUERY_ACTION_LOAD_FB, 0) \ + _(XR_SPACE_QUERY_ACTION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceStorageLocationFB(_) \ + _(XR_SPACE_STORAGE_LOCATION_INVALID_FB, 0) \ + _(XR_SPACE_STORAGE_LOCATION_LOCAL_FB, 1) \ + _(XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpacePersistenceModeFB(_) \ + _(XR_SPACE_PERSISTENCE_MODE_INVALID_FB, 0) \ + _(XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB, 1) \ + _(XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerformanceMetricsCounterUnitMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META, 0) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META, 1) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META, 2) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META, 3) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META, 4) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META, 0x7FFFFFFF) + #define XR_LIST_BITS_XrInstanceCreateFlags(_) #define XR_LIST_BITS_XrSessionCreateFlags(_) @@ -408,6 +774,7 @@ XR_ENUM_STR(XrResult); _(XR_SWAPCHAIN_USAGE_SAMPLED_BIT, 0x00000020) \ _(XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, 0x00000040) \ _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND, 0x00000080) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR, XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND) \ #define XR_LIST_BITS_XrCompositionLayerFlags(_) \ _(XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, 0x00000001) \ @@ -441,16 +808,82 @@ XR_ENUM_STR(XrResult); _(XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 0x00000004) \ _(XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, 0x00000008) \ -#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) \ - _(XR_OVERLAY_SESSION_CREATE_RELAXED_DISPLAY_TIME_BIT_EXTX, 0x00000001) \ +#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) #define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \ _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \ +#define XR_LIST_BITS_XrCompositionLayerImageLayoutFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB, 0x00000001) \ + #define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \ _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \ _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \ +#define XR_LIST_BITS_XrCompositionLayerSecureContentFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrHandTrackingAimFlagsFB(_) \ + _(XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB, 0x00000001) \ + _(XR_HAND_TRACKING_AIM_VALID_BIT_FB, 0x00000002) \ + _(XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB, 0x00000004) \ + _(XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB, 0x00000008) \ + _(XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB, 0x00000010) \ + _(XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB, 0x00000020) \ + _(XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB, 0x00000040) \ + _(XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB, 0x00000080) \ + _(XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB, 0x00000100) \ + +#define XR_LIST_BITS_XrSwapchainCreateFoveationFlagsFB(_) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainStateFoveationFlagsFB(_) + +#define XR_LIST_BITS_XrKeyboardTrackingFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_EXISTS_BIT_FB, 0x00000001) \ + _(XR_KEYBOARD_TRACKING_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_REMOTE_BIT_FB, 0x00000004) \ + _(XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrKeyboardTrackingQueryFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrTriangleMeshFlagsFB(_) \ + _(XR_TRIANGLE_MESH_MUTABLE_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughFlagsFB(_) \ + _(XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughStateChangedFlagsFB(_) \ + _(XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB, 0x00000004) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrRenderModelFlagsFB(_) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB, 0x00000001) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \ + _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerSettingsFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB, 0x00000002) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB, 0x00000004) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrPerformanceMetricsCounterFlagsMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META, 0x00000001) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META, 0x00000002) \ + _(XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META, 0x00000004) \ + #define XR_LIST_STRUCT_XrApiLayerProperties(_) \ _(type) \ _(next) \ @@ -1213,6 +1646,19 @@ XR_ENUM_STR(XrResult); _(anchor) \ _(poseInAnchorSpace) \ +#define XR_LIST_STRUCT_XrCompositionLayerImageLayoutFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrCompositionLayerAlphaBlendFB(_) \ + _(type) \ + _(next) \ + _(srcFactorColor) \ + _(dstFactorColor) \ + _(srcFactorAlpha) \ + _(dstFactorAlpha) \ + #define XR_LIST_STRUCT_XrViewConfigurationDepthRangeEXT(_) \ _(type) \ _(next) \ @@ -1236,6 +1682,23 @@ XR_ENUM_STR(XrResult); _(nodeId) \ _(pose) \ +#define XR_LIST_STRUCT_XrSpatialGraphStaticNodeBindingCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesGetInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeId) \ + _(poseInNodeSpace) \ + #define XR_LIST_STRUCT_XrSystemHandTrackingPropertiesEXT(_) \ _(type) \ _(next) \ @@ -1404,11 +1867,45 @@ XR_ENUM_STR(XrResult); _(holographicSpace) \ _(coreWindow) \ +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionInfoMSFT(_) \ + _(type) \ + _(next) \ + _(reprojectionMode) \ + +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionPlaneOverrideMSFT(_) \ + _(type) \ + _(next) \ + _(position) \ + _(normal) \ + _(velocity) \ + #define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \ _(type) \ _(next) \ _(createFlags) \ +#define XR_LIST_STRUCT_XrSwapchainStateBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSecureContentFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrInteractionProfileDpadBindingEXT(_) \ + _(type) \ + _(next) \ + _(binding) \ + _(actionSet) \ + _(forceThreshold) \ + _(forceThresholdReleased) \ + _(centerRegion) \ + _(wedgeAngle) \ + _(isSticky) \ + _(onHaptic) \ + _(offHaptic) \ + #define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \ _(type) \ _(next) \ @@ -1419,17 +1916,765 @@ XR_ENUM_STR(XrResult); _(onHaptic) \ _(offHaptic) \ +#define XR_LIST_STRUCT_XrHandJointsMotionRangeInfoEXT(_) \ + _(type) \ + _(next) \ + _(handJointsMotionRange) \ + +#define XR_LIST_STRUCT_XrUuidMSFT(_) \ + _(bytes) \ + +#define XR_LIST_STRUCT_XrSceneObserverCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneSphereBoundMSFT(_) \ + _(center) \ + _(radius) \ + +#define XR_LIST_STRUCT_XrSceneOrientedBoxBoundMSFT(_) \ + _(pose) \ + _(extents) \ + +#define XR_LIST_STRUCT_XrSceneFrustumBoundMSFT(_) \ + _(pose) \ + _(fov) \ + _(farDistance) \ + +#define XR_LIST_STRUCT_XrSceneBoundsMSFT(_) \ + _(space) \ + _(time) \ + _(sphereCount) \ + _(spheres) \ + _(boxCount) \ + _(boxes) \ + _(frustumCount) \ + _(frustums) \ + +#define XR_LIST_STRUCT_XrNewSceneComputeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(requestedFeatureCount) \ + _(requestedFeatures) \ + _(consistency) \ + _(bounds) \ + +#define XR_LIST_STRUCT_XrVisualMeshComputeLodInfoMSFT(_) \ + _(type) \ + _(next) \ + _(lod) \ + +#define XR_LIST_STRUCT_XrSceneComponentMSFT(_) \ + _(componentType) \ + _(id) \ + _(parentId) \ + _(updateTime) \ + +#define XR_LIST_STRUCT_XrSceneComponentsMSFT(_) \ + _(type) \ + _(next) \ + _(componentCapacityInput) \ + _(componentCountOutput) \ + _(components) \ + +#define XR_LIST_STRUCT_XrSceneComponentsGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationMSFT(_) \ + _(flags) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationsMSFT(_) \ + _(type) \ + _(next) \ + _(locationCount) \ + _(locations) \ + +#define XR_LIST_STRUCT_XrSceneComponentsLocateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(componentIdCount) \ + _(componentIds) \ + +#define XR_LIST_STRUCT_XrSceneObjectMSFT(_) \ + _(objectType) \ + +#define XR_LIST_STRUCT_XrSceneObjectsMSFT(_) \ + _(type) \ + _(next) \ + _(sceneObjectCount) \ + _(sceneObjects) \ + +#define XR_LIST_STRUCT_XrSceneComponentParentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(parentId) \ + +#define XR_LIST_STRUCT_XrSceneObjectTypesFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(objectTypeCount) \ + _(objectTypes) \ + +#define XR_LIST_STRUCT_XrScenePlaneMSFT(_) \ + _(alignment) \ + _(size) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrScenePlanesMSFT(_) \ + _(type) \ + _(next) \ + _(scenePlaneCount) \ + _(scenePlanes) \ + +#define XR_LIST_STRUCT_XrScenePlaneAlignmentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(alignmentCount) \ + _(alignments) \ + +#define XR_LIST_STRUCT_XrSceneMeshMSFT(_) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrSceneMeshesMSFT(_) \ + _(type) \ + _(next) \ + _(sceneMeshCount) \ + _(sceneMeshes) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(meshBufferId) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneMeshVertexBufferMSFT(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint32MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint16MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSerializedSceneFragmentDataGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(sceneFragmentId) \ + +#define XR_LIST_STRUCT_XrDeserializeSceneFragmentMSFT(_) \ + _(bufferSize) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrSceneDeserializeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(fragmentCount) \ + _(fragments) \ + #define XR_LIST_STRUCT_XrEventDataDisplayRefreshRateChangedFB(_) \ _(type) \ _(next) \ _(fromDisplayRefreshRate) \ _(toDisplayRefreshRate) \ +#define XR_LIST_STRUCT_XrViveTrackerPathsHTCX(_) \ + _(type) \ + _(next) \ + _(persistentPath) \ + _(rolePath) \ + +#define XR_LIST_STRUCT_XrEventDataViveTrackerConnectedHTCX(_) \ + _(type) \ + _(next) \ + _(paths) \ + +#define XR_LIST_STRUCT_XrSystemFacialTrackingPropertiesHTC(_) \ + _(type) \ + _(next) \ + _(supportEyeFacialTracking) \ + _(supportLipFacialTracking) \ + +#define XR_LIST_STRUCT_XrFacialExpressionsHTC(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(sampleTime) \ + _(expressionCount) \ + _(expressionWeightings) \ + +#define XR_LIST_STRUCT_XrFacialTrackerCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(facialTrackingType) \ + #define XR_LIST_STRUCT_XrSystemColorSpacePropertiesFB(_) \ _(type) \ _(next) \ _(colorSpace) \ +#define XR_LIST_STRUCT_XrVector4sFB(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrHandTrackingMeshFB(_) \ + _(type) \ + _(next) \ + _(jointCapacityInput) \ + _(jointCountOutput) \ + _(jointBindPoses) \ + _(jointRadii) \ + _(jointParents) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertexPositions) \ + _(vertexNormals) \ + _(vertexUVs) \ + _(vertexBlendIndices) \ + _(vertexBlendWeights) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrHandTrackingScaleFB(_) \ + _(type) \ + _(next) \ + _(sensorOutput) \ + _(currentOutput) \ + _(overrideHandScale) \ + _(overrideValueInput) \ + +#define XR_LIST_STRUCT_XrHandTrackingAimStateFB(_) \ + _(type) \ + _(next) \ + _(status) \ + _(aimPose) \ + _(pinchStrengthIndex) \ + _(pinchStrengthMiddle) \ + _(pinchStrengthRing) \ + _(pinchStrengthLittle) \ + +#define XR_LIST_STRUCT_XrHandCapsuleFB(_) \ + _(points) \ + _(radius) \ + _(joint) \ + +#define XR_LIST_STRUCT_XrHandTrackingCapsulesStateFB(_) \ + _(type) \ + _(next) \ + _(capsules) \ + +#define XR_LIST_STRUCT_XrSystemSpatialEntityPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsSpatialEntity) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpaceComponentStatusSetInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + _(enabled) \ + _(timeout) \ + +#define XR_LIST_STRUCT_XrSpaceComponentStatusFB(_) \ + _(type) \ + _(next) \ + _(enabled) \ + _(changePending) \ + +#define XR_LIST_STRUCT_XrUuidEXT(_) \ + _(data) \ + +#define XR_LIST_STRUCT_XrEventDataSpatialAnchorCreateCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceSetStatusCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(componentType) \ + _(enabled) \ + +#define XR_LIST_STRUCT_XrFoveationProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainCreateInfoFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSwapchainStateFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(profile) \ + +#define XR_LIST_STRUCT_XrFoveationLevelProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(level) \ + _(verticalOffset) \ + _(dynamic) \ + +#define XR_LIST_STRUCT_XrSystemKeyboardTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsKeyboardTracking) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingDescriptionFB(_) \ + _(trackedKeyboardId) \ + _(size) \ + _(flags) \ + _(name) \ + +#define XR_LIST_STRUCT_XrKeyboardSpaceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(trackedKeyboardId) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingQueryFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrTriangleMeshCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(windingOrder) \ + _(vertexCount) \ + _(vertexBuffer) \ + _(triangleCount) \ + _(indexBuffer) \ + +#define XR_LIST_STRUCT_XrSystemPassthroughPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsPassthrough) \ + +#define XR_LIST_STRUCT_XrPassthroughCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrPassthroughLayerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(passthrough) \ + _(flags) \ + _(purpose) \ + +#define XR_LIST_STRUCT_XrCompositionLayerPassthroughFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(space) \ + _(layerHandle) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(layer) \ + _(mesh) \ + _(baseSpace) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceTransformFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrPassthroughStyleFB(_) \ + _(type) \ + _(next) \ + _(textureOpacityFactor) \ + _(edgeColor) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToRgbaFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToMonoFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughBrightnessContrastSaturationFB(_) \ + _(type) \ + _(next) \ + _(brightness) \ + _(contrast) \ + _(saturation) \ + +#define XR_LIST_STRUCT_XrEventDataPassthroughStateChangedFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelPathInfoFB(_) \ + _(type) \ + _(next) \ + _(path) \ + +#define XR_LIST_STRUCT_XrRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(vendorId) \ + _(modelName) \ + _(modelKey) \ + _(modelVersion) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelBufferFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRenderModelLoadInfoFB(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +#define XR_LIST_STRUCT_XrSystemRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsRenderModelLoading) \ + +#define XR_LIST_STRUCT_XrRenderModelCapabilitiesRequestFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrViewLocateFoveatedRenderingVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrFoveatedViewConfigurationViewVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrSystemFoveatedRenderingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsFoveatedRendering) \ + +#define XR_LIST_STRUCT_XrCompositionLayerDepthTestVARJO(_) \ + _(type) \ + _(next) \ + _(depthTestRangeNearZ) \ + _(depthTestRangeFarZ) \ + +#define XR_LIST_STRUCT_XrSystemMarkerTrackingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsMarkerTracking) \ + +#define XR_LIST_STRUCT_XrEventDataMarkerTrackingUpdateVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(isActive) \ + _(isPredicted) \ + _(time) \ + +#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(poseInMarkerSpace) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \ + _(name) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorPersistenceName) \ + _(spatialAnchor) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorStore) \ + _(spatialAnchorPersistenceName) \ + +#define XR_LIST_STRUCT_XrSpaceQueryInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpaceFilterInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpaceQueryInfoFB(_) \ + _(type) \ + _(next) \ + _(queryAction) \ + _(maxResultCount) \ + _(timeout) \ + _(filter) \ + _(excludeFilter) \ + +#define XR_LIST_STRUCT_XrSpaceStorageLocationFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(location) \ + +#define XR_LIST_STRUCT_XrSpaceUuidFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(uuidCount) \ + _(uuids) \ + +#define XR_LIST_STRUCT_XrSpaceComponentFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSpaceQueryResultFB(_) \ + _(space) \ + _(uuid) \ + +#define XR_LIST_STRUCT_XrSpaceQueryResultsFB(_) \ + _(type) \ + _(next) \ + _(resultCapacityInput) \ + _(resultCountOutput) \ + _(results) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceQueryResultsAvailableFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceQueryCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +#define XR_LIST_STRUCT_XrSpaceSaveInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + _(persistenceMode) \ + +#define XR_LIST_STRUCT_XrSpaceEraseInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceSaveCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceEraseCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +#define XR_LIST_STRUCT_XrSwapchainImageFoveationVulkanFB(_) \ + _(type) \ + _(next) \ + _(image) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateAndroidSurfaceDimensionsFB(_) \ + _(type) \ + _(next) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerOpenGLESFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerVulkanFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(mipmapMode) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(motionVectorSubImage) \ + _(appSpaceDeltaPose) \ + _(depthSubImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +#define XR_LIST_STRUCT_XrSystemSpaceWarpPropertiesFB(_) \ + _(type) \ + _(next) \ + _(recommendedMotionVectorImageRectWidth) \ + _(recommendedMotionVectorImageRectHeight) \ + +#define XR_LIST_STRUCT_XrExtent3DfFB(_) \ + _(width) \ + _(height) \ + _(depth) \ + +#define XR_LIST_STRUCT_XrOffset3DfFB(_) \ + _(x) \ + _(y) \ + _(z) \ + +#define XR_LIST_STRUCT_XrRect3DfFB(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrSemanticLabelsFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRoomLayoutFB(_) \ + _(type) \ + _(next) \ + _(floorUuid) \ + _(ceilingUuid) \ + _(wallUuidCapacityInput) \ + _(wallUuidCountOutput) \ + _(wallUuids) \ + +#define XR_LIST_STRUCT_XrBoundary2DFB(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSpaceContainerFB(_) \ + _(type) \ + _(next) \ + _(uuidCapacityInput) \ + _(uuidCountOutput) \ + _(uuids) \ + +#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \ + _(type) \ + _(next) \ + _(leftHandIntensity) \ + _(rightHandIntensity) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSettingsFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + +#define XR_LIST_STRUCT_XrVulkanSwapchainCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(additionalCreateFlags) \ + _(additionalUsageFlags) \ + +#define XR_LIST_STRUCT_XrPerformanceMetricsStateMETA(_) \ + _(type) \ + _(next) \ + _(enabled) \ + +#define XR_LIST_STRUCT_XrPerformanceMetricsCounterMETA(_) \ + _(type) \ + _(next) \ + _(counterFlags) \ + _(counterUnit) \ + _(uintValue) \ + _(floatValue) \ + #define XR_LIST_STRUCTURE_TYPES_CORE(_) \ @@ -1502,8 +2747,13 @@ XR_ENUM_STR(XrResult); _(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ _(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \ _(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \ + _(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \ + _(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \ _(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \ _(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \ + _(XrSpatialGraphStaticNodeBindingCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesGetInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT) \ _(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \ _(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \ _(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \ @@ -1526,9 +2776,106 @@ XR_ENUM_STR(XrResult); _(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \ _(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \ _(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \ + _(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \ + _(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \ + _(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \ + _(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \ _(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + _(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \ + _(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \ + _(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \ + _(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \ + _(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \ + _(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \ + _(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \ + _(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \ + _(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \ + _(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \ + _(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \ + _(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \ + _(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \ + _(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \ + _(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \ + _(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \ + _(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \ + _(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \ + _(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \ + _(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \ + _(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \ + _(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \ _(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \ + _(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \ + _(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \ + _(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \ _(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \ + _(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \ + _(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \ + _(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \ + _(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \ + _(XrSystemSpatialEntityPropertiesFB, XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB) \ + _(XrSpatialAnchorCreateInfoFB, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB) \ + _(XrSpaceComponentStatusSetInfoFB, XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB) \ + _(XrSpaceComponentStatusFB, XR_TYPE_SPACE_COMPONENT_STATUS_FB) \ + _(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ + _(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ + _(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \ + _(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \ + _(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + _(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \ + _(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \ + _(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \ + _(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \ + _(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \ + _(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \ + _(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \ + _(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \ + _(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \ + _(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \ + _(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \ + _(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \ + _(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \ + _(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \ + _(XrPassthroughBrightnessContrastSaturationFB, XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB) \ + _(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \ + _(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \ + _(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \ + _(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \ + _(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelCapabilitiesRequestFB, XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB) \ + _(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \ + _(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \ + _(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \ + _(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \ + _(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \ + _(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ + _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ + _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \ + _(XrSpaceStorageLocationFilterInfoFB, XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB) \ + _(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \ + _(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \ + _(XrSpaceQueryResultsFB, XR_TYPE_SPACE_QUERY_RESULTS_FB) \ + _(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ + _(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ + _(XrSpaceSaveInfoFB, XR_TYPE_SPACE_SAVE_INFO_FB) \ + _(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \ + _(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ + _(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \ + _(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \ + _(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \ + _(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \ + _(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \ + _(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \ + _(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \ + _(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \ + _(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \ + _(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \ + _(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \ + _(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \ @@ -1605,12 +2952,22 @@ XR_ENUM_STR(XrResult); #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ _(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ _(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ #else #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) #endif +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) +#endif + #if defined(XR_USE_GRAPHICS_API_VULKAN) #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ @@ -1620,6 +2977,9 @@ XR_ENUM_STR(XrResult); _(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ _(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ _(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + _(XrVulkanSwapchainCreateInfoMETA, XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META) \ #else @@ -1631,21 +2991,13 @@ XR_ENUM_STR(XrResult); _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ #else #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) #endif -#if defined(XR_USE_PLATFORM_ANDROID) && defined(XR_USE_GRAPHICS_API_OPENGL_ES) -#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ - _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ - - -#else -#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) -#endif - #if defined(XR_USE_PLATFORM_EGL) #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ @@ -1674,9 +3026,9 @@ XR_ENUM_STR(XrResult); XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ - XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ @@ -1707,6 +3059,8 @@ XR_ENUM_STR(XrResult); _(XR_VARJO_quad_views, 38) \ _(XR_MSFT_unbounded_reference_space, 39) \ _(XR_MSFT_spatial_anchor, 40) \ + _(XR_FB_composition_layer_image_layout, 41) \ + _(XR_FB_composition_layer_alpha_blend, 42) \ _(XR_MND_headless, 43) \ _(XR_OCULUS_android_session_state_enable, 45) \ _(XR_EXT_view_configuration_depth_range, 47) \ @@ -1723,9 +3077,14 @@ XR_ENUM_STR(XrResult); _(XR_EXT_win32_appcontainer_compatible, 58) \ _(XR_EPIC_view_configuration_fov, 60) \ _(XR_MSFT_holographic_window_attachment, 64) \ + _(XR_MSFT_composition_layer_reprojection, 67) \ _(XR_HUAWEI_controller_interaction, 70) \ _(XR_FB_android_surface_swapchain_create, 71) \ + _(XR_FB_swapchain_update_state, 72) \ + _(XR_FB_composition_layer_secure_content, 73) \ + _(XR_EXT_dpad_binding, 79) \ _(XR_VALVE_analog_threshold, 80) \ + _(XR_EXT_hand_joints_motion_range, 81) \ _(XR_KHR_loader_init, 89) \ _(XR_KHR_loader_init_android, 90) \ _(XR_KHR_vulkan_enable2, 91) \ @@ -1733,10 +3092,52 @@ XR_ENUM_STR(XrResult); _(XR_EXT_samsung_odyssey_controller, 95) \ _(XR_EXT_hp_mixed_reality_controller, 96) \ _(XR_MND_swapchain_usage_input_attachment_bit, 97) \ + _(XR_MSFT_scene_understanding, 98) \ + _(XR_MSFT_scene_understanding_serialization, 99) \ _(XR_FB_display_refresh_rate, 102) \ _(XR_HTC_vive_cosmos_controller_interaction, 103) \ + _(XR_HTCX_vive_tracker_interaction, 104) \ + _(XR_HTC_facial_tracking, 105) \ + _(XR_HTC_vive_focus3_controller_interaction, 106) \ + _(XR_HTC_hand_interaction, 107) \ + _(XR_HTC_vive_wrist_tracker_interaction, 108) \ _(XR_FB_color_space, 109) \ + _(XR_FB_hand_tracking_mesh, 111) \ + _(XR_FB_hand_tracking_aim, 112) \ + _(XR_FB_hand_tracking_capsules, 113) \ + _(XR_FB_spatial_entity, 114) \ + _(XR_FB_foveation, 115) \ + _(XR_FB_foveation_configuration, 116) \ + _(XR_FB_keyboard_tracking, 117) \ + _(XR_FB_triangle_mesh, 118) \ + _(XR_FB_passthrough, 119) \ + _(XR_FB_render_model, 120) \ _(XR_KHR_binding_modification, 121) \ + _(XR_VARJO_foveated_rendering, 122) \ + _(XR_VARJO_composition_layer_depth_test, 123) \ + _(XR_VARJO_environment_depth_estimation, 124) \ + _(XR_VARJO_marker_tracking, 125) \ + _(XR_VARJO_view_offset, 126) \ + _(XR_MSFT_spatial_anchor_persistence, 143) \ + _(XR_ULTRALEAP_hand_tracking_forearm, 150) \ + _(XR_FB_spatial_entity_query, 157) \ + _(XR_FB_spatial_entity_storage, 159) \ + _(XR_OCULUS_audio_device_guid, 160) \ + _(XR_FB_foveation_vulkan, 161) \ + _(XR_FB_swapchain_update_state_android_surface, 162) \ + _(XR_FB_swapchain_update_state_opengl_es, 163) \ + _(XR_FB_swapchain_update_state_vulkan, 164) \ + _(XR_KHR_swapchain_usage_input_attachment_bit, 166) \ + _(XR_FB_space_warp, 172) \ + _(XR_FB_scene, 176) \ + _(XR_EXT_palm_pose, 177) \ + _(XR_ALMALENCE_digital_lens_control, 197) \ + _(XR_FB_spatial_entity_container, 200) \ + _(XR_FB_passthrough_keyboard_hands, 204) \ + _(XR_FB_composition_layer_settings, 205) \ + _(XR_META_vulkan_swapchain_create_info, 228) \ + _(XR_META_performance_metrics, 233) \ + _(XR_EXT_uuid, 300) \ #endif diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0b74ce0881..86463708b7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,6 +3,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip android.useAndroidX=true android.enableJetifier=true diff --git a/headless/Compare.cpp b/headless/Compare.cpp index 76254d005a..e99b496b30 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -138,11 +138,11 @@ protected: BufferedLineReader() { } - virtual bool HasMoreLines() { + bool HasMoreLines() { return pos_ != data_.npos; } - virtual std::string ReadLine() { + std::string ReadLine() { size_t next = data_.find('\n', pos_); if (next == data_.npos) { std::string result = data_.substr(pos_); @@ -399,6 +399,7 @@ double ScreenshotComparer::Compare(const Path &screenshotFilename) { if (header[0] == 'B' && header[1] == 'M') { reference_ = (u32 *)calloc(stride_ * h_, sizeof(u32)); + referenceStride_ = stride_; asBitmap_ = true; // The bitmap header is 14 + 40 bytes. We could validate it but the test would fail either way. if (reference_ && loader->ReadAt(14 + 40, sizeof(u32), stride_ * h_, reference_) != stride_ * h_) { @@ -424,6 +425,8 @@ double ScreenshotComparer::Compare(const Path &screenshotFilename) { reference_ = nullptr; return -1.0f; } + + referenceStride_ = width; } } else { error_ = "Unable to read screenshot: " + screenshotFilename.ToVisualString(); @@ -439,15 +442,15 @@ double ScreenshotComparer::Compare(const Path &screenshotFilename) { if (asBitmap_) { // The reference is flipped and BGRA by default for the common BMP compare case. for (u32 y = 0; y < h_; ++y) { - u32 yoff = y * stride_; + u32 yoff = y * referenceStride_; for (u32 x = 0; x < w_; ++x) errors += ComparePixel(pixels_[y * stride_ + x], reference_[yoff + x]); } } else { // Just convert to BGRA for simplicity. - ConvertRGBA8888ToBGRA8888(reference_, reference_, h_ * stride_); + ConvertRGBA8888ToBGRA8888(reference_, reference_, h_ * referenceStride_); for (u32 y = 0; y < h_; ++y) { - u32 yoff = (h_ - y - 1) * stride_; + u32 yoff = (h_ - y - 1) * referenceStride_; for (u32 x = 0; x < w_; ++x) errors += ComparePixel(pixels_[y * stride_ + x], reference_[yoff + x]); } @@ -486,7 +489,7 @@ bool ScreenshotComparer::SaveVisualComparisonPNG(const Path &resultFilename) { if (asBitmap_) { // The reference is flipped and BGRA by default for the common BMP compare case. for (u32 y = 0; y < h_; ++y) { - u32 yoff = y * stride_; + u32 yoff = y * referenceStride_; u32 comparisonRow = (h_ - y - 1) * 2 * w_ * 2; for (u32 x = 0; x < w_; ++x) { PlotVisualComparison(comparison.get(), comparisonRow + x * 2, pixels_[y * stride_ + x], reference_[yoff + x]); @@ -495,7 +498,7 @@ bool ScreenshotComparer::SaveVisualComparisonPNG(const Path &resultFilename) { } else { // Reference is already in BGRA either way. for (u32 y = 0; y < h_; ++y) { - u32 yoff = (h_ - y - 1) * stride_; + u32 yoff = (h_ - y - 1) * referenceStride_; u32 comparisonRow = (h_ - y - 1) * 2 * w_ * 2; for (u32 x = 0; x < w_; ++x) { PlotVisualComparison(comparison.get(), comparisonRow + x * 2, pixels_[y * stride_ + x], reference_[yoff + x]); diff --git a/headless/Compare.h b/headless/Compare.h index 0ddd702af8..2a59039cdd 100644 --- a/headless/Compare.h +++ b/headless/Compare.h @@ -58,6 +58,7 @@ protected: u32 *reference_ = nullptr; bool asBitmap_ = false; std::string error_; + u32 referenceStride_ = 0; u32 stride_; u32 w_; u32 h_; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 5b2b8adfd3..fa63a489e1 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -1,6 +1,8 @@ // Headless version of PPSSPP, for testing using http://code.google.com/p/pspautotests/ . // See headless.txt. // To build on non-windows systems, just run CMake in the SDL directory, it will build both a normal ppsspp and the headless version. +// Example command line to run a test in the VS debugger (useful to debug failures): +// > --root pspautotests/tests/../ --compare --timeout=5 --graphics=software pspautotests/tests/cpu/cpu_alu/cpu_alu.prx #include "ppsspp_config.h" #include @@ -63,7 +65,7 @@ bool audioRecording_State() { return false; } class PrintfLogger : public LogListener { public: - void Log(const LogMessage &message) { + void Log(const LogMessage &message) override { switch (message.level) { case LogTypes::LVERBOSE: fprintf(stderr, "V %s", message.msg.c_str()); @@ -203,8 +205,9 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops); PSP_BeginHostFrame(); - if (coreParameter.graphicsContext && coreParameter.graphicsContext->GetDrawContext()) - coreParameter.graphicsContext->GetDrawContext()->BeginFrame(); + Draw::DrawContext *draw = coreParameter.graphicsContext ? coreParameter.graphicsContext->GetDrawContext() : nullptr; + if (draw) + draw->BeginFrame(); bool passed = true; double deadline = time_now_d() + opt.timeout; @@ -238,8 +241,14 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const } PSP_EndHostFrame(); - if (coreParameter.graphicsContext && coreParameter.graphicsContext->GetDrawContext()) - coreParameter.graphicsContext->GetDrawContext()->EndFrame(); + if (draw) { + draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless"); + // Vulkan may get angry if we don't do a final present. + if (gpu) + gpu->CopyDisplayToOutput(true); + + draw->EndFrame(); + } PSP_Shutdown(); @@ -413,9 +422,11 @@ int main(int argc, const char* argv[]) // Never report from tests. g_Config.sReportHost.clear(); g_Config.bAutoSaveSymbolMap = false; - g_Config.iRenderingMode = FB_BUFFERED_MODE; + g_Config.bSkipBufferEffects = false; + g_Config.bSkipGPUReadbacks = false; g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. + g_Config.iMultiSampleLevel = 0; g_Config.bVertexCache = false; g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR; @@ -432,7 +443,6 @@ int main(int argc, const char* argv[]) g_Config.bVertexDecoderJit = true; g_Config.bSoftwareRendering = coreParameter.gpuCore == GPUCORE_SOFTWARE; g_Config.bSoftwareRenderingJit = true; - g_Config.bBlockTransferGPU = true; g_Config.iSplineBezierQuality = 2; g_Config.bHighQualityDepth = true; g_Config.bMemStickInserted = true; diff --git a/history.md b/history.md index 2191439617..153f8f96b5 100644 --- a/history.md +++ b/history.md @@ -1,5 +1,87 @@ This is history moved out from README.md, which was getting a bit long. +What's new in 1.12.3 +==================== +* Fix background music speed. A couple translation fixes. + +What's new in 1.12.2 +==================== +* Fix joystick detection bug on Android. + +What's new in 1.12.1 +==================== +* Bug fixes (control mapping fix, popup menus in the Windows debugger, a few crashfixes) + +What's new in 1.12 +================== + +Platform support: +* Add support for Android 12 Scoped Storage restrictions ([#11997]) +* iOS: Fix multitouch tracking ([#5099]) +* Android: Fix screenshot orientation on Vulkan ([#14053]) +* Linux: Improve support for system FFmpeg 3.1+ ([#14176], [#14188], [#14199]) +* libretro: Always enable function hooks ([#14145]) +* AMD: Enable Vulkan rendering on a thread ([#13864]) +* Add iOS version detection, turn off JIT on bootup if >= 14.3. ([#14201]) +* iOS: Try a different JIT detection method, thanks Halo-Michael ([#14241]) +* Windows: Restore window size correctly ([#14317]) + +Game fixes: +* Fix NBA Live 08 loading ([#8288]) +* Display Open Season title screen correctly ([#13252]) +* Fix Metal Gear Solid Peace Walker Chinese Patched blue screen ([#14127]) +* Load Ape Academy 2 correctly ([#14271]) +* Many more... + +Graphics and Sound: +* Add new texture filtering mode "Auto Max Quality" ([#14789]) +* Fix Princess Maker 5 Portable half screen in Vulkan ([#13741]) +* Fix Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off ([#14167]) +* Support texture replacement filtering overrides ([#14230]) +* Fix Yarudora Portable: Double Cast's FMVs artifacting ([#13759]) +* Fix Sims 2 Castaway/Pets EA Logo glitched out ([#13146]) +* Fix bad size & position on Japanese & Numbers & Alphabets ([#14209]) +* Implement basic depth texturing for OpenGL ([#14042]) +* Google Cardboard fixes ([#14966], [#14768]) +* Correct mini-map update in Z.H.P. ([#14069]) +* Fix crash in vertex jit on ARM32 ([#14879]) +* Add a setting for reverb volume ([#14711]) +* Option to switch to new devices or not, on Windows. + +UI: +* Add a setting for choosing background animation in PPSSPP's menus ([#14313], [#14818], [#14810], [#14347]) +* Add CRC calculation on game info screen and feedback screen ([#14000], [#14041]) +* Add a Storage tab to System Information with some path info ([#14224], [#14238]) +* Track and show memory allocation / usage information in debugger ([#14056]) +* Allow searching within the savedata manager ([#14237]) +* Enable postshaders to access previous frame ([#14528]) +* Add missing Japanese keyboard symbol ([#14548]) +* Add Reset button on crash screen, allow load state and related ([#14708]) +* Implement save state load and save undo ([#14676], [#14679], [#14697]) +* A lot of minor debugger improvements + +Controls: +* New analog stick calibration menu ([#14596]) +* Improved combo button and moved settings to Customize Touch Control -> Customize -> Custom button ([#13869]) +* Improved tilt control, allow to change axis ([#12530]) +* Add a visual means of control mapping ([#14769]) +* Add basic motion gesture support ([#13107]) +* Fix touch control DPAD not getting input when dragged over, and make touch analog drag not activate other buttons ([#14843]) +* Allow adjusting touch control analog stick head size ([#14480]) + +Adhoc/Network: +* Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data ([#14140]) +* Always enable TCPNoDelay to improve response time ([#14235]) +* Fix Teenage Mutant Ninja Turtles multiplayer ([#14284]) +* Fix FlatOut Head On multiplayer ([#14290]) +* Prevent flooding Adhoc Server with connection attempts ([#14335]) +* Fix crashing issue when leaving a multiplayer game room (ie. GTA Vice City Stories) ([#14342]) +* Fix stuck issue when scanning AP to Recruit on MGS:PW ([#14345]) +* Fix possible crash issue on blocking socket implementation (ie. Kao Challengers) ([#14466]) +* Create GameMode's socket after Master and all Replicas have been created (ie. Fading Shadows) ([#14492]) +* Reduce HLE delays due to multiplayer performance regressions (ie. Ys vs. Sora no Kiseki) ([#14513]) +* Fix socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy ([#14849]) + What's new in 1.11.3 ==================== * Fix for graphics glitches in the on-screen keyboard @@ -783,3 +865,66 @@ go to see there http://forums.ppsspp.org/showthread.php?tid=3595&pid=59241#pid59 [#14132]: https://github.com/hrydgard/ppsspp/issues/14132 "Io: Truncate reads/writes to valid memory" [#14134]: https://github.com/hrydgard/ppsspp/issues/14134 "Android: Ensure shutdown waits for render" [#14129]: https://github.com/hrydgard/ppsspp/issues/14129 "GPU: Force reinterpret off without copy image" +[#11997]: https://github.com/hrydgard/ppsspp/issues/11997 "Android 12 scoped storage hell" +[#5099]: https://github.com/hrydgard/ppsspp/issues/5099 "IOS touch controls problems." +[#14053]: https://github.com/hrydgard/ppsspp/issues/14053 "Toggle screenshot minor issue." +[#14176]: https://github.com/hrydgard/ppsspp/issues/14176 "Remove deprecated API calls for new FFmpeg 4.3.x" +[#14188]: https://github.com/hrydgard/ppsspp/issues/14188 "Additional fixes for FFmpeg 3.1+" +[#14199]: https://github.com/hrydgard/ppsspp/issues/14199 "Mpeg: Set low latency flag for video decode" +[#14145]: https://github.com/hrydgard/ppsspp/issues/14145 "libretro: Remove \"Unsafe FuncReplacements\" option." +[#13864]: https://github.com/hrydgard/ppsspp/issues/13864 "Vulkan: Remove #10097 hack for newer AMD drivers" +[#14201]: https://github.com/hrydgard/ppsspp/issues/14201 "Add iOS version detection, turn off JIT on bootup if >= 14.3." +[#14241]: https://github.com/hrydgard/ppsspp/issues/14241 "iOS: Try a different JIT detection method, thanks Halo-Michael." +[#14317]: https://github.com/hrydgard/ppsspp/issues/14317 "Window size restarts on closing" +[#8288]: https://github.com/hrydgard/ppsspp/issues/8288 "NBA live 08 Invalid address and hang" +[#13252]: https://github.com/hrydgard/ppsspp/issues/13252 "Open Season Title Screen does not display" +[#14127]: https://github.com/hrydgard/ppsspp/issues/14127 "Metal Gear Solid Peace Walker Chinese Patched blue screen" +[#14271]: https://github.com/hrydgard/ppsspp/issues/14271 "Ape Academy 2 is broken on versions after 1.8.0(?) - tested on latest nightly and 1.11.3" +[#14789]: https://github.com/hrydgard/ppsspp/issues/14789 "Add new texture filtering mode \"Auto Max Quality\"" +[#13741]: https://github.com/hrydgard/ppsspp/issues/13741 "Princess Maker 5 Portable half screen in Vulkan" +[#14167]: https://github.com/hrydgard/ppsspp/issues/14167 "[Android] Pro Yakyu Spirits 2010 (NPJH50234): Rendering errors with hardware transform off" +[#14230]: https://github.com/hrydgard/ppsspp/issues/14230 "Support texture replacement filtering overrides" +[#13759]: https://github.com/hrydgard/ppsspp/issues/13759 "Yarudora Portable: Double Cast" +[#13146]: https://github.com/hrydgard/ppsspp/issues/13146 "Sims 2 Castaway/Pets EA Logo glitched out - 1.10.2" +[#14209]: https://github.com/hrydgard/ppsspp/issues/14209 "Fix Size & Position jpn0.pgf/ltn0.pgf/ltn2.pgf/ltn4.pgf/ltn6.pgf" +[#14042]: https://github.com/hrydgard/ppsspp/issues/14042 "Implement basic depth texturing for OpenGL" +[#14966]: https://github.com/hrydgard/ppsspp/issues/14966 "Config: Correct cardboard setting ini load" +[#14768]: https://github.com/hrydgard/ppsspp/issues/14768 "Fix the math in cardboard VR mode for wide aspect ratios" +[#14069]: https://github.com/hrydgard/ppsspp/issues/14069 "Mini-Map in Z.H.P. Updates Incorrectly Without Software Rendering" +[#14879]: https://github.com/hrydgard/ppsspp/issues/14879 "vertexjit: Correct morph flag alpha check assert" +[#14711]: https://github.com/hrydgard/ppsspp/issues/14711 "Sas: Add option to control reverb volume" +[#14313]: https://github.com/hrydgard/ppsspp/issues/14313 "Add a setting for choosing background animation in PPSSPP's menus" +[#14818]: https://github.com/hrydgard/ppsspp/issues/14818 "Focus based moving background" +[#14810]: https://github.com/hrydgard/ppsspp/issues/14810 "Wave animation" +[#14347]: https://github.com/hrydgard/ppsspp/issues/14347 "UI: Add BG animation for recent games" +[#14000]: https://github.com/hrydgard/ppsspp/issues/14000 "Add CRC32 calc" +[#14041]: https://github.com/hrydgard/ppsspp/issues/14041 "UI: Add button to show CRC on feedback screen" +[#14224]: https://github.com/hrydgard/ppsspp/issues/14224 "Add a Storage tab to System Information with some path info" +[#14238]: https://github.com/hrydgard/ppsspp/issues/14238 "UI: Wrap long info items and cleanup storage display" +[#14056]: https://github.com/hrydgard/ppsspp/issues/14056 "Track memory allocations and writes for debug info" +[#14237]: https://github.com/hrydgard/ppsspp/issues/14237 "Add initial search to savedata manager" +[#14528]: https://github.com/hrydgard/ppsspp/issues/14528 "Postshader: Let shaders use the previous frame" +[#14548]: https://github.com/hrydgard/ppsspp/issues/14548 "Add some PPSSPP's Japanese keyboard" +[#14708]: https://github.com/hrydgard/ppsspp/issues/14708 "Add Reset button on crash screen, allow load state and related" +[#14676]: https://github.com/hrydgard/ppsspp/issues/14676 "Add savestate undo UI" +[#14679]: https://github.com/hrydgard/ppsspp/issues/14679 "Savestate load undo" +[#14697]: https://github.com/hrydgard/ppsspp/issues/14697 "Add undo last save as well" +[#14596]: https://github.com/hrydgard/ppsspp/issues/14596 "Replace the \"Test Analogs\" screen with a new screen that lets you directly try the settings." +[#13869]: https://github.com/hrydgard/ppsspp/issues/13869 "Make combo button more generic" +[#12530]: https://github.com/hrydgard/ppsspp/issues/12530 "Allow tilt input on Z instead of X" +[#14769]: https://github.com/hrydgard/ppsspp/issues/14769 "Add a visual means of control mapping" +[#13107]: https://github.com/hrydgard/ppsspp/issues/13107 "Basic mappable motion gesture" +[#14843]: https://github.com/hrydgard/ppsspp/issues/14843 "DPad drag fixes" +[#14480]: https://github.com/hrydgard/ppsspp/issues/14480 "Configurable analog head size" +[#14140]: https://github.com/hrydgard/ppsspp/issues/14140 "[Adhoc] Fix multiplayer issue on MGS:PW due to detecting an incorrect source port on incoming data" +[#14235]: https://github.com/hrydgard/ppsspp/issues/14235 "[Adhoc] Always enable TCPNoDelay to improve response time" +[#14284]: https://github.com/hrydgard/ppsspp/issues/14284 "[Adhoc] Fix Teenage Mutant Ninja Turtles Multiplayer" +[#14290]: https://github.com/hrydgard/ppsspp/issues/14290 "Fix FlatOut Head On multiplayer." +[#14335]: https://github.com/hrydgard/ppsspp/issues/14335 "[Adhoc] Prevent flooding Adhoc Server with connection attempts" +[#14342]: https://github.com/hrydgard/ppsspp/issues/14342 "[AdhocMatching] Fix crashing issue when leaving a multiplayer game room" +[#14345]: https://github.com/hrydgard/ppsspp/issues/14345 "[APctl] Fix stuck issue when scanning AP to Recruit on MGS:PW" +[#14466]: https://github.com/hrydgard/ppsspp/issues/14466 "[Adhoc] Fix possible crash issue on blocking socket implementation." +[#14492]: https://github.com/hrydgard/ppsspp/issues/14492 "[AdhocGameMode] Create GameMode's socket after Master and all Replicas have been created" +[#14513]: https://github.com/hrydgard/ppsspp/issues/14513 "[Adhoc] Reducing HLE delays due to Mutiplayer performance regressions" +[#14849]: https://github.com/hrydgard/ppsspp/issues/14849 "[Adhoc] Fix Socket error 10014 on Windows when hosting a game of Vulcanus Seek and Destroy" +[#11974]: https://github.com/hrydgard/ppsspp/issues/11974 "[Linux] [Vulkan] Toggle fullscreen doesn't update display properly" \ No newline at end of file diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt index 69efea8980..d04cc155e5 100644 --- a/libretro/CMakeLists.txt +++ b/libretro/CMakeLists.txt @@ -22,6 +22,10 @@ if(ANDROID) endif() if(NOT MSVC) - target_link_libraries(ppsspp_libretro "-Wl,-Bsymbolic") + if (IOS) + target_link_libraries(ppsspp_libretro "-Wl") + else() + target_link_libraries(ppsspp_libretro "-Wl,-Bsymbolic") + endif() endif() target_link_libraries(ppsspp_libretro ${LinkCommon}) diff --git a/libretro/Makefile b/libretro/Makefile index 088ad22267..e732ddfba2 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -311,139 +311,28 @@ else ifeq ($(platform), emscripten) -Drglgen_resolve_symbols=mupen_rglgen_resolve_symbols PLATFORM_EXT = unix -# Windows MSVC 2017 all architectures -else ifneq (,$(findstring windows_msvc2017,$(platform))) - - PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) - ifneq (,$(findstring desktop,$(PlatformSuffix))) - WinPartition = desktop - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 - LDFLAGS += -MANIFEST -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 - LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib - else ifneq (,$(findstring uwp,$(PlatformSuffix))) - WinPartition = uwp - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB - LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO - LIBS += WindowsApp.lib - endif - - ifeq ($(DEBUG), 1) - MSVC2017CompileFlags += -DEBUG - endif - - CFLAGS += $(MSVC2017CompileFlags) -nologo - CXXFLAGS += $(MSVC2017CompileFlags) -nologo -EHsc -DARMIPS_USE_STD_FILESYSTEM - - TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) - - CC = cl.exe - CXX = cl.exe - - SPACE := - SPACE := $(SPACE) $(SPACE) - BACKSLASH := - BACKSLASH := \$(BACKSLASH) - filter_out1 = $(filter-out $(firstword $1),$1) - filter_out2 = $(call filter_out1,$(call filter_out1,$1)) - - reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>/dev/null))) - fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) - - b1 := ( - b2 := ) - ProgramFiles86w := $(ProgramFiles$(b1)x86$(b2)) - ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") - - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir := $(WindowsSdkDir) - - WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) - WindowsSDKVersion := $(WindowsSDKVersion) - - VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools - VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise - VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional - VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community - - VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) - endif - VsInstallRoot := $(VsInstallRoot) - - VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') - VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) - VcCompilerLibDir := $(VcCompilerToolsDir)/lib/$(TargetArchMoniker) - - WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared") - WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt") - WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um") - WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)") - WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)") - - LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerLibDir)") - INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") - - # For some reason the HostX86 compiler doesn't like compiling for x64 - # ("no such file" opening a shared library), and vice-versa. - # Work around it for now by using the strictly x86 compiler for x86, and x64 for x64. - # NOTE: What about ARM? - ifneq (,$(findstring x64,$(TargetArchMoniker))) - override TARGET_ARCH = x86_64 - VCCompilerToolsBinDir := $(VcCompilerToolsDir)/bin/HostX64/$(TargetArchMoniker) - LIB := $(LIB);$(CORE_DIR)/dx9sdk/Lib/x64 - else - override TARGET_ARCH = x86 - VCCompilerToolsBinDir := $(VcCompilerToolsDir)/bin/HostX86/$(TargetArchMoniker) - LIB := $(LIB);$(CORE_DIR)/dx9sdk/Lib/x86 - endif - - PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)"):$(PATH) - PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") - - export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) - export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir);$(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib - TARGET := $(TARGET_NAME)_libretro.dll - PSS_STYLE :=2 - LDFLAGS += -DLL - PLATFORM_EXT = win32 - FFMPEGINCFLAGS += -I$(FFMPEGDIR)/Windows/$(TARGET_ARCH)/include - FFMPEGLIBDIR := $(FFMPEGDIR)/Windows/$(TARGET_ARCH)/lib - FFMPEGLDFLAGS += -LIBPATH:$(FFMPEGLIBDIR) - GL_LIB := opengl32.lib - LDFLAGS += ws2_32.lib user32.lib shell32.lib avcodec.lib avutil.lib swresample.lib swscale.lib avformat.lib advapi32.lib winmm.lib gdi32.lib d3d9.lib d3dx9.lib Iphlpapi.lib - -# Windows MSVC 2019 all architectures +# Windows MSVC all architectures else ifneq (,$(findstring windows_msvc2019,$(platform))) PlatformSuffix = $(subst windows_msvc2019_,,$(platform)) ifneq (,$(findstring desktop,$(PlatformSuffix))) WinPartition = desktop - MSVC2019CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 + MSVCCompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -D_UNICODE -DUNICODE -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 LDFLAGS += -MANIFEST -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib else ifneq (,$(findstring uwp,$(PlatformSuffix))) WinPartition = uwp - MSVC2019CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB + MSVCCompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO LIBS += WindowsApp.lib endif ifeq ($(DEBUG), 1) - MSVC2019CompileFlags += -DEBUG + MSVCCompileFlags += -DEBUG endif - CFLAGS += $(MSVC2019CompileFlags) -nologo - CXXFLAGS += $(MSVC2019CompileFlags) -nologo -EHsc -DARMIPS_USE_STD_FILESYSTEM + CFLAGS += $(MSVCCompileFlags) -nologo + CXXFLAGS += $(MSVCCompileFlags) -nologo -EHsc -DARMIPS_USE_STD_FILESYSTEM TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) @@ -460,10 +349,9 @@ else ifneq (,$(findstring windows_msvc2019,$(platform))) reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>/dev/null))) fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) - b1 := ( - b2 := ) - ProgramFiles86w := $(ProgramFiles$(b1)x86$(b2)) - ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") + VSCommand := bash VSWhere.sh -latest -property installationPath + VSInstallPathw := $(shell cmd /c "$(VSCommand)") + VSInstallPath := $(shell cygpath "$(VSInstallPathw)") WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) @@ -474,22 +362,7 @@ else ifneq (,$(findstring windows_msvc2019,$(platform))) WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) WindowsSDKVersion := $(WindowsSDKVersion) - VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2019/BuildTools - VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2019/Enterprise - VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2019/Professional - VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2019/Community - - VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) - endif - VsInstallRoot := $(VsInstallRoot) + VsInstallRoot := $(VSInstallPath) VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 375792b296..a3f925b107 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -16,6 +16,7 @@ INCFLAGS += \ -I$(CORE_DIR) \ -I$(COMMONDIR) \ -I$(CORE_DIR)/libretro \ + -I$(EXTDIR)/openxr \ -I$(EXTDIR)/glslang \ -I$(EXTDIR)/native \ -I$(EXTDIR)/zlib \ @@ -36,133 +37,131 @@ INCFLAGS += \ -I$(EXTDIR)/xxhash \ -I$(EXTDIR)/glew -ifeq ($(PLATFORM_EXT), android) - INCFLAGS += -I$(EXTDIR)/libzip - SOURCES_C += \ - $(EXTDIR)/libzip/zip_add.c \ - $(EXTDIR)/libzip/zip_add_dir.c \ - $(EXTDIR)/libzip/zip_add_entry.c \ - $(EXTDIR)/libzip/zip_algorithm_deflate.c \ - $(EXTDIR)/libzip/zip_buffer.c \ - $(EXTDIR)/libzip/zip_close.c \ - $(EXTDIR)/libzip/zip_delete.c \ - $(EXTDIR)/libzip/zip_dir_add.c \ - $(EXTDIR)/libzip/zip_dirent.c \ - $(EXTDIR)/libzip/zip_discard.c \ - $(EXTDIR)/libzip/zip_entry.c \ - $(EXTDIR)/libzip/zip_error.c \ - $(EXTDIR)/libzip/zip_error_clear.c \ - $(EXTDIR)/libzip/zip_error_get.c \ - $(EXTDIR)/libzip/zip_error_get_sys_type.c \ - $(EXTDIR)/libzip/zip_error_strerror.c \ - $(EXTDIR)/libzip/zip_error_to_str.c \ - $(EXTDIR)/libzip/zip_extra_field.c \ - $(EXTDIR)/libzip/zip_extra_field_api.c \ - $(EXTDIR)/libzip/zip_fclose.c \ - $(EXTDIR)/libzip/zip_fdopen.c \ - $(EXTDIR)/libzip/zip_file_add.c \ - $(EXTDIR)/libzip/zip_file_error_clear.c \ - $(EXTDIR)/libzip/zip_file_error_get.c \ - $(EXTDIR)/libzip/zip_file_get_comment.c \ - $(EXTDIR)/libzip/zip_file_get_external_attributes.c \ - $(EXTDIR)/libzip/zip_file_get_offset.c \ - $(EXTDIR)/libzip/zip_file_rename.c \ - $(EXTDIR)/libzip/zip_file_replace.c \ - $(EXTDIR)/libzip/zip_file_set_comment.c \ - $(EXTDIR)/libzip/zip_file_set_encryption.c \ - $(EXTDIR)/libzip/zip_file_set_external_attributes.c \ - $(EXTDIR)/libzip/zip_file_set_mtime.c \ - $(EXTDIR)/libzip/zip_file_strerror.c \ - $(EXTDIR)/libzip/zip_fopen.c \ - $(EXTDIR)/libzip/zip_fopen_encrypted.c \ - $(EXTDIR)/libzip/zip_fopen_index.c \ - $(EXTDIR)/libzip/zip_fopen_index_encrypted.c \ - $(EXTDIR)/libzip/zip_fread.c \ - $(EXTDIR)/libzip/zip_fseek.c \ - $(EXTDIR)/libzip/zip_ftell.c \ - $(EXTDIR)/libzip/zip_get_archive_comment.c \ - $(EXTDIR)/libzip/zip_get_archive_flag.c \ - $(EXTDIR)/libzip/zip_get_encryption_implementation.c \ - $(EXTDIR)/libzip/zip_get_file_comment.c \ - $(EXTDIR)/libzip/zip_get_name.c \ - $(EXTDIR)/libzip/zip_get_num_entries.c \ - $(EXTDIR)/libzip/zip_get_num_files.c \ - $(EXTDIR)/libzip/zip_hash.c \ - $(EXTDIR)/libzip/zip_io_util.c \ - $(EXTDIR)/libzip/zip_libzip_version.c \ - $(EXTDIR)/libzip/zip_memdup.c \ - $(EXTDIR)/libzip/zip_name_locate.c \ - $(EXTDIR)/libzip/zip_new.c \ - $(EXTDIR)/libzip/zip_open.c \ - $(EXTDIR)/libzip/zip_pkware.c \ - $(EXTDIR)/libzip/zip_progress.c \ - $(EXTDIR)/libzip/zip_rename.c \ - $(EXTDIR)/libzip/zip_replace.c \ - $(EXTDIR)/libzip/zip_set_archive_comment.c \ - $(EXTDIR)/libzip/zip_set_archive_flag.c \ - $(EXTDIR)/libzip/zip_set_default_password.c \ - $(EXTDIR)/libzip/zip_set_file_comment.c \ - $(EXTDIR)/libzip/zip_set_file_compression.c \ - $(EXTDIR)/libzip/zip_set_name.c \ - $(EXTDIR)/libzip/zip_source_accept_empty.c \ - $(EXTDIR)/libzip/zip_source_begin_write.c \ - $(EXTDIR)/libzip/zip_source_begin_write_cloning.c \ - $(EXTDIR)/libzip/zip_source_buffer.c \ - $(EXTDIR)/libzip/zip_source_call.c \ - $(EXTDIR)/libzip/zip_source_close.c \ - $(EXTDIR)/libzip/zip_source_commit_write.c \ - $(EXTDIR)/libzip/zip_source_compress.c \ - $(EXTDIR)/libzip/zip_source_crc.c \ - $(EXTDIR)/libzip/zip_source_error.c \ - $(EXTDIR)/libzip/zip_source_file_common.c \ - $(EXTDIR)/libzip/zip_source_file_stdio.c \ - $(EXTDIR)/libzip/zip_source_free.c \ - $(EXTDIR)/libzip/zip_source_function.c \ - $(EXTDIR)/libzip/zip_source_get_file_attributes.c \ - $(EXTDIR)/libzip/zip_source_is_deleted.c \ - $(EXTDIR)/libzip/zip_source_layered.c \ - $(EXTDIR)/libzip/zip_source_open.c \ - $(EXTDIR)/libzip/zip_source_pkware_decode.c \ - $(EXTDIR)/libzip/zip_source_pkware_encode.c \ - $(EXTDIR)/libzip/zip_source_read.c \ - $(EXTDIR)/libzip/zip_source_remove.c \ - $(EXTDIR)/libzip/zip_source_rollback_write.c \ - $(EXTDIR)/libzip/zip_source_seek.c \ - $(EXTDIR)/libzip/zip_source_seek_write.c \ - $(EXTDIR)/libzip/zip_source_stat.c \ - $(EXTDIR)/libzip/zip_source_supports.c \ - $(EXTDIR)/libzip/zip_source_tell.c \ - $(EXTDIR)/libzip/zip_source_tell_write.c \ - $(EXTDIR)/libzip/zip_source_window.c \ - $(EXTDIR)/libzip/zip_source_write.c \ - $(EXTDIR)/libzip/zip_source_zip.c \ - $(EXTDIR)/libzip/zip_source_zip_new.c \ - $(EXTDIR)/libzip/zip_stat.c \ - $(EXTDIR)/libzip/zip_stat_index.c \ - $(EXTDIR)/libzip/zip_stat_init.c \ - $(EXTDIR)/libzip/zip_strerror.c \ - $(EXTDIR)/libzip/zip_string.c \ - $(EXTDIR)/libzip/zip_unchange.c \ - $(EXTDIR)/libzip/zip_unchange_all.c \ - $(EXTDIR)/libzip/zip_unchange_archive.c \ - $(EXTDIR)/libzip/zip_unchange_data.c \ - $(EXTDIR)/libzip/zip_utf-8.c \ - $(EXTDIR)/libzip/zip_err_str.c +INCFLAGS += -I$(EXTDIR)/libzip +SOURCES_C += \ + $(EXTDIR)/libzip/zip_add.c \ + $(EXTDIR)/libzip/zip_add_dir.c \ + $(EXTDIR)/libzip/zip_add_entry.c \ + $(EXTDIR)/libzip/zip_algorithm_deflate.c \ + $(EXTDIR)/libzip/zip_buffer.c \ + $(EXTDIR)/libzip/zip_close.c \ + $(EXTDIR)/libzip/zip_delete.c \ + $(EXTDIR)/libzip/zip_dir_add.c \ + $(EXTDIR)/libzip/zip_dirent.c \ + $(EXTDIR)/libzip/zip_discard.c \ + $(EXTDIR)/libzip/zip_entry.c \ + $(EXTDIR)/libzip/zip_error.c \ + $(EXTDIR)/libzip/zip_error_clear.c \ + $(EXTDIR)/libzip/zip_error_get.c \ + $(EXTDIR)/libzip/zip_error_get_sys_type.c \ + $(EXTDIR)/libzip/zip_error_strerror.c \ + $(EXTDIR)/libzip/zip_error_to_str.c \ + $(EXTDIR)/libzip/zip_extra_field.c \ + $(EXTDIR)/libzip/zip_extra_field_api.c \ + $(EXTDIR)/libzip/zip_fclose.c \ + $(EXTDIR)/libzip/zip_fdopen.c \ + $(EXTDIR)/libzip/zip_file_add.c \ + $(EXTDIR)/libzip/zip_file_error_clear.c \ + $(EXTDIR)/libzip/zip_file_error_get.c \ + $(EXTDIR)/libzip/zip_file_get_comment.c \ + $(EXTDIR)/libzip/zip_file_get_external_attributes.c \ + $(EXTDIR)/libzip/zip_file_get_offset.c \ + $(EXTDIR)/libzip/zip_file_rename.c \ + $(EXTDIR)/libzip/zip_file_replace.c \ + $(EXTDIR)/libzip/zip_file_set_comment.c \ + $(EXTDIR)/libzip/zip_file_set_encryption.c \ + $(EXTDIR)/libzip/zip_file_set_external_attributes.c \ + $(EXTDIR)/libzip/zip_file_set_mtime.c \ + $(EXTDIR)/libzip/zip_file_strerror.c \ + $(EXTDIR)/libzip/zip_fopen.c \ + $(EXTDIR)/libzip/zip_fopen_encrypted.c \ + $(EXTDIR)/libzip/zip_fopen_index.c \ + $(EXTDIR)/libzip/zip_fopen_index_encrypted.c \ + $(EXTDIR)/libzip/zip_fread.c \ + $(EXTDIR)/libzip/zip_fseek.c \ + $(EXTDIR)/libzip/zip_ftell.c \ + $(EXTDIR)/libzip/zip_get_archive_comment.c \ + $(EXTDIR)/libzip/zip_get_archive_flag.c \ + $(EXTDIR)/libzip/zip_get_encryption_implementation.c \ + $(EXTDIR)/libzip/zip_get_file_comment.c \ + $(EXTDIR)/libzip/zip_get_name.c \ + $(EXTDIR)/libzip/zip_get_num_entries.c \ + $(EXTDIR)/libzip/zip_get_num_files.c \ + $(EXTDIR)/libzip/zip_hash.c \ + $(EXTDIR)/libzip/zip_io_util.c \ + $(EXTDIR)/libzip/zip_libzip_version.c \ + $(EXTDIR)/libzip/zip_memdup.c \ + $(EXTDIR)/libzip/zip_name_locate.c \ + $(EXTDIR)/libzip/zip_new.c \ + $(EXTDIR)/libzip/zip_open.c \ + $(EXTDIR)/libzip/zip_pkware.c \ + $(EXTDIR)/libzip/zip_progress.c \ + $(EXTDIR)/libzip/zip_rename.c \ + $(EXTDIR)/libzip/zip_replace.c \ + $(EXTDIR)/libzip/zip_set_archive_comment.c \ + $(EXTDIR)/libzip/zip_set_archive_flag.c \ + $(EXTDIR)/libzip/zip_set_default_password.c \ + $(EXTDIR)/libzip/zip_set_file_comment.c \ + $(EXTDIR)/libzip/zip_set_file_compression.c \ + $(EXTDIR)/libzip/zip_set_name.c \ + $(EXTDIR)/libzip/zip_source_accept_empty.c \ + $(EXTDIR)/libzip/zip_source_begin_write.c \ + $(EXTDIR)/libzip/zip_source_begin_write_cloning.c \ + $(EXTDIR)/libzip/zip_source_buffer.c \ + $(EXTDIR)/libzip/zip_source_call.c \ + $(EXTDIR)/libzip/zip_source_close.c \ + $(EXTDIR)/libzip/zip_source_commit_write.c \ + $(EXTDIR)/libzip/zip_source_compress.c \ + $(EXTDIR)/libzip/zip_source_crc.c \ + $(EXTDIR)/libzip/zip_source_error.c \ + $(EXTDIR)/libzip/zip_source_file_common.c \ + $(EXTDIR)/libzip/zip_source_file_stdio.c \ + $(EXTDIR)/libzip/zip_source_free.c \ + $(EXTDIR)/libzip/zip_source_function.c \ + $(EXTDIR)/libzip/zip_source_get_file_attributes.c \ + $(EXTDIR)/libzip/zip_source_is_deleted.c \ + $(EXTDIR)/libzip/zip_source_layered.c \ + $(EXTDIR)/libzip/zip_source_open.c \ + $(EXTDIR)/libzip/zip_source_pkware_decode.c \ + $(EXTDIR)/libzip/zip_source_pkware_encode.c \ + $(EXTDIR)/libzip/zip_source_read.c \ + $(EXTDIR)/libzip/zip_source_remove.c \ + $(EXTDIR)/libzip/zip_source_rollback_write.c \ + $(EXTDIR)/libzip/zip_source_seek.c \ + $(EXTDIR)/libzip/zip_source_seek_write.c \ + $(EXTDIR)/libzip/zip_source_stat.c \ + $(EXTDIR)/libzip/zip_source_supports.c \ + $(EXTDIR)/libzip/zip_source_tell.c \ + $(EXTDIR)/libzip/zip_source_tell_write.c \ + $(EXTDIR)/libzip/zip_source_window.c \ + $(EXTDIR)/libzip/zip_source_write.c \ + $(EXTDIR)/libzip/zip_source_zip.c \ + $(EXTDIR)/libzip/zip_source_zip_new.c \ + $(EXTDIR)/libzip/zip_stat.c \ + $(EXTDIR)/libzip/zip_stat_index.c \ + $(EXTDIR)/libzip/zip_stat_init.c \ + $(EXTDIR)/libzip/zip_strerror.c \ + $(EXTDIR)/libzip/zip_string.c \ + $(EXTDIR)/libzip/zip_unchange.c \ + $(EXTDIR)/libzip/zip_unchange_all.c \ + $(EXTDIR)/libzip/zip_unchange_archive.c \ + $(EXTDIR)/libzip/zip_unchange_data.c \ + $(EXTDIR)/libzip/zip_utf-8.c \ + $(EXTDIR)/libzip/zip_err_str.c - ifeq ($(PLATFORM_EXT), win32) - SOURCES_C += \ - $(EXTDIR)/libzip/zip_source_file_win32.c \ - $(EXTDIR)/libzip/zip_source_file_win32_named.c \ - $(EXTDIR)/libzip/zip_source_file_win32_utf16.c \ - $(EXTDIR)/libzip/zip_source_file_win32_utf8.c \ - $(EXTDIR)/libzip/zip_source_file_win32_ansi.c \ - $(EXTDIR)/libzip/zip_random_win32.c - else - SOURCES_C += \ - $(EXTDIR)/libzip/zip_mkstempm.c \ - $(EXTDIR)/libzip/zip_source_file_stdio_named.c \ - $(EXTDIR)/libzip/zip_random_unix.c - endif +ifeq ($(PLATFORM_EXT), win32) + SOURCES_C += \ + $(EXTDIR)/libzip/zip_source_file_win32.c \ + $(EXTDIR)/libzip/zip_source_file_win32_named.c \ + $(EXTDIR)/libzip/zip_source_file_win32_utf16.c \ + $(EXTDIR)/libzip/zip_source_file_win32_utf8.c \ + $(EXTDIR)/libzip/zip_source_file_win32_ansi.c \ + $(EXTDIR)/libzip/zip_random_win32.c +else + SOURCES_C += \ + $(EXTDIR)/libzip/zip_mkstempm.c \ + $(EXTDIR)/libzip/zip_source_file_stdio_named.c \ + $(EXTDIR)/libzip/zip_random_unix.c endif SOURCES_C += $(LIBRETRODIR)/ext/glew/glew.c @@ -263,6 +262,7 @@ SOURCES_CXX += \ $(COMMONDIR)/GPU/Vulkan/VulkanContext.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanDebug.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanImage.cpp \ + $(COMMONDIR)/GPU/Vulkan/VulkanFramebuffer.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanMemory.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanProfiler.cpp \ $(COMMONDIR)/GPU/Vulkan/VulkanBarrier.cpp \ @@ -282,12 +282,14 @@ SOURCES_CXX += \ $(COMMONDIR)/Net/Sinks.cpp \ $(COMMONDIR)/Net/URL.cpp \ $(COMMONDIR)/Net/WebsocketServer.cpp \ + $(COMMONDIR)/Render/ManagedTexture.cpp \ $(COMMONDIR)/Render/DrawBuffer.cpp \ $(COMMONDIR)/Render/TextureAtlas.cpp \ $(COMMONDIR)/Serialize/Serializer.cpp \ $(COMMONDIR)/Thread/ThreadUtil.cpp \ $(COMMONDIR)/Thread/ParallelLoop.cpp \ $(COMMONDIR)/Thread/ThreadManager.cpp \ + $(COMMONDIR)/UI/AsyncImageFileView.cpp \ $(COMMONDIR)/UI/Root.cpp \ $(COMMONDIR)/UI/Screen.cpp \ $(COMMONDIR)/UI/UI.cpp \ @@ -314,6 +316,15 @@ SOURCES_CXX += \ $(COMMONDIR)/StringUtils.cpp \ $(COMMONDIR)/TimeUtil.cpp +SOURCES_CXX += \ + $(COMMONDIR)/VR/OpenXRLoader.cpp \ + $(COMMONDIR)/VR/PPSSPPVR.cpp \ + $(COMMONDIR)/VR/VRBase.cpp \ + $(COMMONDIR)/VR/VRMath.cpp \ + $(COMMONDIR)/VR/VRFramebuffer.cpp \ + $(COMMONDIR)/VR/VRInput.cpp \ + $(COMMONDIR)/VR/VRRenderer.cpp + SOURCES_C +=\ $(COMMONDIR)/GPU/OpenGL/gl3stub.c \ $(COMMONDIR)/Math/fast/fast_matrix.c @@ -608,8 +619,7 @@ SOURCES_CXX += \ $(COREDIR)/Util/PPGeDraw.cpp \ $(COREDIR)/Util/AudioFormat.cpp \ $(COREDIR)/Util/PortManager.cpp \ - $(CORE_DIR)/UI/TextureUtil.cpp \ - $(CORE_DIR)/UI/GameInfoCache.cpp + $(CORE_DIR)/UI/GameInfoCache.cpp SOURCES_CXX += $(COREDIR)/HLE/__sceAudio.cpp diff --git a/libretro/README_WINDOWS.txt b/libretro/README_WINDOWS.txt index 4e8f6236af..b126a8f9af 100644 --- a/libretro/README_WINDOWS.txt +++ b/libretro/README_WINDOWS.txt @@ -1,28 +1,29 @@ -Install msys. - -Follow the guide here to set up your MSYS installation for retroarch compilation: - -https://docs.libretro.com/development/retroarch/compilation/windows/ - -You can probably really skip most of the packages but you need make: - -pacman -S make - -"Install" the plugin in Retroarch. - -Then use the following in msys: - -cd libretro -make platform=windows_msvc2019_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores - -Note that the latter part copies the DLL/PDB into wherever retroarch reads it from. Might need to adjust the path, -and adjust -j32 depending on your number of logical CPUs - might not need that many threads (or you might need more...). - -(plain make without a platform parameter doesn't work - g++ isn't able to build the D3D11 stuff, or at least it fails to link). - -To debug from within MSVC, open retroarch.exe (or retroarch_debug.exe) as a Project/Solution, then open a few of the cpp files, -set some breakpoints and just launch using F5. - -Useful libretro/vulkan sample code: - -https://github.com/libretro/libretro-samples/blob/master/video/vulkan/vk_rendering/libretro-test.c +Install msys. + +Follow the guide here to set up your MSYS installation for retroarch compilation: + +https://docs.libretro.com/development/retroarch/compilation/windows/ + +You can probably really skip most of the packages but you need make: + +pacman -S make + +"Install" the plugin in Retroarch. + +Then use the following in msys: + +cd libretro + +make platform=windows_msvc2019_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores + +Note that the latter part copies the DLL/PDB into wherever retroarch reads it from. Might need to adjust the path, +and adjust -j32 depending on your number of logical CPUs - might not need that many threads (or you might need more...). + +(plain make without a platform parameter doesn't work - g++ isn't able to build the D3D11 stuff, or at least it fails to link). + +To debug from within MSVC, open retroarch.exe (or retroarch_debug.exe) as a Project/Solution, then open a few of the cpp files, +set some breakpoints and just launch using F5. + +Useful libretro/vulkan sample code: + +https://github.com/libretro/libretro-samples/blob/master/video/vulkan/vk_rendering/libretro-test.c diff --git a/libretro/VSWhere.sh b/libretro/VSWhere.sh new file mode 100644 index 0000000000..7ae8b0933e --- /dev/null +++ b/libretro/VSWhere.sh @@ -0,0 +1,2 @@ +#!/bin/sh +"$(cygpath "$(env | awk -F= '/^ProgramFiles\(x86\)=/ { print $2; }')/Microsoft Visual Studio/Installer/vswhere.exe")" "$@" \ No newline at end of file diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 9b4a20bd97..40c737399e 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -23,6 +23,7 @@ #include "Common/File/VFS/VFS.h" #include "Common/File/VFS/AssetReader.h" #include "Common/Data/Text/I18n.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -36,6 +37,8 @@ #include "Core/System.h" #include "Core/CoreTiming.h" #include "Core/HW/Display.h" +#include "Core/CwCheat.h" +#include "Core/ELF/ParamSFO.h" #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" @@ -45,6 +48,7 @@ #include "libretro/libretro.h" #include "libretro/LibretroGraphicsContext.h" +#include "libretro/libretro_core_options.h" #if PPSSPP_PLATFORM(ANDROID) #include @@ -81,6 +85,10 @@ #define VSYNC_SWAP_INTERVAL_RUN_SPEED_THRESHOLD 5.0f static bool libretro_supports_bitmasks = false; +static bool libretro_supports_option_categories = false; +static bool show_ip_address_options = true; +static bool show_upnp_port_option = true; +static bool show_detect_frame_rate_option = true; static std::string changeProAdhocServer; namespace Libretro @@ -428,239 +436,72 @@ class PrintfLogger : public LogListener }; static PrintfLogger *printfLogger; -template class RetroOption -{ - public: - RetroOption(const char *id, const char *name, std::initializer_list> list) : id_(id), name_(name), list_(list.begin(), list.end()) {} - RetroOption(const char *id, const char *name, std::initializer_list list) : id_(id), name_(name) { - for (auto option : list) - list_.push_back({ option, (T)list_.size() }); - } - RetroOption(const char *id, const char *name, T first, std::initializer_list list) : id_(id), name_(name) { - for (auto option : list) - list_.push_back({ option, first + (int)list_.size() }); - } - RetroOption(const char *id, const char *name, T first, int count, int step = 1) : id_(id), name_(name) { - for (T i = first; i < first + count; i += step) - list_.push_back({ std::to_string(i), i }); - } - RetroOption(const char *id, const char *name, bool initial) : id_(id), name_(name) { - list_.push_back({ initial ? "enabled" : "disabled", initial }); - list_.push_back({ !initial ? "enabled" : "disabled", !initial }); - } - - retro_variable GetOptions() - { - if (options_.empty()) - { - options_ = name_; - options_.push_back(';'); - for (auto &option : list_) - { - if (option.first == list_.begin()->first) - options_ += std::string(" ") + option.first; - else - options_ += std::string("|") + option.first; - } - } - return { id_, options_.c_str() }; - } - - bool Update(T *dest) - { - retro_variable var{ id_ }; - T val = list_.front().second; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - for (auto option : list_) - { - if (option.first == var.value) - { - val = option.second; - break; - } - } - } - - if (*dest != val) - { - *dest = val; - return true; - } - - return false; - } - - void Show(bool show) - { - struct retro_core_option_display optionDisplay{id_, show}; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &optionDisplay); - } - - void Set(const char *val) - { - struct retro_variable var{id_, val}; - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, &var); - } - - private: - const char *id_; - const char *name_; - std::string options_; - std::vector> list_; -}; - -#define MAC_INITIALIZER_LIST \ -{ \ - {"0", "0"}, \ - {"1", "1"}, \ - {"2", "2"}, \ - {"3", "3"}, \ - {"4", "4"}, \ - {"5", "5"}, \ - {"6", "6"}, \ - {"7", "7"}, \ - {"8", "8"}, \ - {"9", "9"}, \ - {"a", "a"}, \ - {"b", "b"}, \ - {"c", "c"}, \ - {"d", "d"}, \ - {"e", "e"}, \ - {"f", "f"} \ -} - -static RetroOption ppsspp_cpu_core("ppsspp_cpu_core", "CPU Core", { { "JIT", CPUCore::JIT }, { "IR JIT", CPUCore::IR_JIT }, { "Interpreter", CPUCore::INTERPRETER } }); -static RetroOption ppsspp_locked_cpu_speed("ppsspp_locked_cpu_speed", "Locked CPU Speed", { { "off", 0 }, { "222MHz", 222 }, { "266MHz", 266 }, { "333MHz", 333 } }); -static RetroOption ppsspp_language("ppsspp_language", "Language", { { "Automatic", -1 }, { "English", PSP_SYSTEMPARAM_LANGUAGE_ENGLISH }, { "Japanese", PSP_SYSTEMPARAM_LANGUAGE_JAPANESE }, { "French", PSP_SYSTEMPARAM_LANGUAGE_FRENCH }, { "Spanish", PSP_SYSTEMPARAM_LANGUAGE_SPANISH }, { "German", PSP_SYSTEMPARAM_LANGUAGE_GERMAN }, { "Italian", PSP_SYSTEMPARAM_LANGUAGE_ITALIAN }, { "Dutch", PSP_SYSTEMPARAM_LANGUAGE_DUTCH }, { "Portuguese", PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE }, { "Russian", PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN }, { "Korean", PSP_SYSTEMPARAM_LANGUAGE_KOREAN }, { "Chinese Traditional", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL }, { "Chinese Simplified", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED } }); -static RetroOption ppsspp_rendering_mode("ppsspp_rendering_mode", "Rendering Mode", { { "Buffered", FB_BUFFERED_MODE }, { "Skip Buffer Effects", FB_NON_BUFFERED_MODE } }); -static RetroOption ppsspp_auto_frameskip("ppsspp_auto_frameskip", "Auto Frameskip", false); -static RetroOption ppsspp_frameskip("ppsspp_frameskip", "Frameskip", { "Off", "1", "2", "3", "4", "5", "6", "7", "8" }); -static RetroOption ppsspp_frameskiptype("ppsspp_frameskiptype", "Frameskip Type", { {"Number of frames", 0}, {"Percent of FPS", 1} }); -static RetroOption ppsspp_internal_resolution("ppsspp_internal_resolution", "Internal Resolution (Restart)", 1, { "480x272", "960x544", "1440x816", "1920x1088", "2400x1360", "2880x1632", "3360x1904", "3840x2176", "4320x2448", "4800x2720" }); -static RetroOption ppsspp_button_preference("ppsspp_button_preference", "Confirmation Button", { { "Cross", PSP_SYSTEMPARAM_BUTTON_CROSS }, { "Circle", PSP_SYSTEMPARAM_BUTTON_CIRCLE } }); -static RetroOption ppsspp_fast_memory("ppsspp_fast_memory", "Fast Memory (Speedhack)", true); -static RetroOption ppsspp_block_transfer_gpu("ppsspp_block_transfer_gpu", "Block Transfer GPU", true); -static RetroOption ppsspp_inflight_frames("ppsspp_inflight_frames", "Buffered frames (Slower, less lag, restart)", { { "Up to 2", 2 }, { "Up to 1", 1 }, { "No buffer", 0 }, }); -static RetroOption ppsspp_texture_scaling_level("ppsspp_texture_scaling_level", "Texture Scaling Level", { { "Off", 1 }, { "2x", 2 }, { "3x", 3 }, { "4x", 4 }, { "5x", 5 } }); -static RetroOption ppsspp_texture_scaling_type("ppsspp_texture_scaling_type", "Texture Scaling Type", { { "xbrz", TextureScalerCommon::XBRZ }, { "hybrid", TextureScalerCommon::HYBRID }, { "bicubic", TextureScalerCommon::BICUBIC }, { "hybrid_bicubic", TextureScalerCommon::HYBRID_BICUBIC } }); -static RetroOption ppsspp_texture_shader("ppsspp_texture_shader", "Texture Shader (Vulkan only, overrides Texture Scaling Type)", { {"Off", "Off"}, {"2xBRZ", "Tex2xBRZ"}, {"4xBRZ", "Tex4xBRZ"}, {"MMPX", "TexMMPX"} }); -static RetroOption ppsspp_texture_filtering("ppsspp_texture_filtering", "Texture Filtering", { { "Auto", 1 }, { "Nearest", 2 }, { "Linear", 3 }, {"Auto max quality", 4}}); -static RetroOption ppsspp_texture_anisotropic_filtering("ppsspp_texture_anisotropic_filtering", "Anisotropic Filtering", { "off", "2x", "4x", "8x", "16x" }); -static RetroOption ppsspp_lower_resolution_for_effects("ppsspp_lower_resolution_for_effects", "Lower resolution for effects", { {"Off", 0}, {"Safe", 1}, {"Balanced", 2}, {"Aggressive", 3} }); -static RetroOption ppsspp_texture_deposterize("ppsspp_texture_deposterize", "Texture Deposterize", false); -static RetroOption ppsspp_texture_replacement("ppsspp_texture_replacement", "Texture Replacement", false); -static RetroOption ppsspp_gpu_hardware_transform("ppsspp_gpu_hardware_transform", "GPU Hardware T&L", true); -static RetroOption ppsspp_vertex_cache("ppsspp_vertex_cache", "Vertex Cache (Speedhack)", false); -static RetroOption ppsspp_cheats("ppsspp_cheats", "Internal Cheats Support", false); -static RetroOption ppsspp_io_timing_method("ppsspp_io_timing_method", "IO Timing Method", { { "Fast", IOTimingMethods::IOTIMING_FAST }, { "Host", IOTimingMethods::IOTIMING_HOST }, { "Simulate UMD delays", IOTimingMethods::IOTIMING_REALISTIC } }); -static RetroOption ppsspp_frame_duplication("ppsspp_frame_duplication", "Duplicate Frames in 30 Hz Games", false); -static RetroOption ppsspp_detect_vsync_swap_interval("ppsspp_detect_vsync_swap_interval", "Detect Frame Rate Changes (Notify Frontend)", false); -static RetroOption ppsspp_software_skinning("ppsspp_software_skinning", "Software Skinning", true); -static RetroOption ppsspp_ignore_bad_memory_access("ppsspp_ignore_bad_memory_access", "Ignore bad memory accesses", true); -static RetroOption ppsspp_lazy_texture_caching("ppsspp_lazy_texture_caching", "Lazy texture caching (Speedup)", false); -static RetroOption ppsspp_retain_changed_textures("ppsspp_retain_changed_textures", "Retain changed textures (Speedup, mem hog)", false); -static RetroOption ppsspp_force_lag_sync("ppsspp_force_lag_sync", "Force real clock sync (Slower, less lag)", false); -static RetroOption ppsspp_spline_quality("ppsspp_spline_quality", "Spline/Bezier curves quality", { {"Low", 0}, {"Medium", 1}, {"High", 2} }); -static RetroOption ppsspp_enable_wlan("ppsspp_enable_wlan", "Enable Networking/WLAN (beta, may break games)", false); -static RetroOption ppsspp_change_mac_address[] = { - {"ppsspp_change_mac_address01", "MAC address Pt 1: X-:--:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address02", "MAC address Pt 2: -X:--:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address03", "MAC address Pt 3: --:X-:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address04", "MAC address Pt 4: --:-X:--:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address05", "MAC address Pt 5: --:--:X-:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address06", "MAC address Pt 6: --:--:-X:--:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address07", "MAC address Pt 7: --:--:--:X-:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address08", "MAC address Pt 8: --:--:--:-X:--:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address09", "MAC address Pt 9: --:--:--:--:X-:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address10", "MAC address Pt 10: --:--:--:--:-X:--", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address11", "MAC address Pt 11: --:--:--:--:--:X-", MAC_INITIALIZER_LIST}, - {"ppsspp_change_mac_address12", "MAC address Pt 12: --:--:--:--:--:-X", MAC_INITIALIZER_LIST} -}; -static RetroOption ppsspp_wlan_channel("ppsspp_wlan_channel", "WLAN channel", {{"Auto", 0}, {"1", 1}, {"6", 6}, {"11", 11}} ); -static RetroOption ppsspp_enable_builtin_pro_ad_hoc_server("ppsspp_enable_builtin_pro_ad_hoc_server", "Enable built-in PRO ad hoc server", false); -static RetroOption ppsspp_change_pro_ad_hoc_server_address("ppsspp_change_pro_ad_hoc_server_address", "Change PRO ad hoc server IP address (localhost = multiple instances)", { - {"socom.cc", "socom.cc"}, - {"psp.gameplayer.club", "psp.gameplayer.club"}, - {"myneighborsushicat.com", "myneighborsushicat.com"}, - {"localhost", "localhost"}, - {"IP address", "IP address"} -}); -static RetroOption ppsspp_pro_ad_hoc_ipv4[] = { - {"ppsspp_pro_ad_hoc_server_address01", "PRO ad hoc server IP address Pt 1: x--.---.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address02", "PRO ad hoc server IP address Pt 2: -x-.---.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address03", "PRO ad hoc server IP address Pt 3: --x.---.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address04", "PRO ad hoc server IP address Pt 4: ---.x--.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address05", "PRO ad hoc server IP address Pt 5: ---.-x-.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address06", "PRO ad hoc server IP address Pt 6: ---.--x.---.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address07", "PRO ad hoc server IP address Pt 7: ---.---.x--.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address08", "PRO ad hoc server IP address Pt 8: ---.---.-x-.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address09", "PRO ad hoc server IP address Pt 9: ---.---.--x.--- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address10", "PRO ad hoc server IP address Pt 10: ---.---.---.x-- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address11", "PRO ad hoc server IP address Pt 11: ---.---.---.-x- ", 0, 10, 1}, - {"ppsspp_pro_ad_hoc_server_address12", "PRO ad hoc server IP address Pt 12: ---.---.---.--x ", 0, 10, 1} -}; -static RetroOption ppsspp_enable_upnp("ppsspp_enable_upnp", "Enable UPnP (need a few seconds to detect)", false); -static RetroOption ppsspp_upnp_use_original_port("ppsspp_upnp_use_original_port", "UPnP use original port (enabled = PSP compatibility)", true); -static RetroOption ppsspp_port_offset("ppsspp_port_offset", "Port offset (0 = PSP compatibility)", 0, 65001, 1000); -static RetroOption ppsspp_minimum_timeout("ppsspp_minimum timeout", "Minimum timeout (override in ms, 0 = default))", 0, 5001, 100); -static RetroOption ppsspp_forced_first_connect("ppsspp_forced_first_connect", "Forced first connect (faster connect)", false); - static bool set_variable_visibility(void) { + struct retro_core_option_display option_display; + struct retro_variable var; bool updated = false; - if (ppsspp_change_pro_ad_hoc_server_address.Update(&changeProAdhocServer)) - updated = true; + // Show/hide IP address options + bool show_ip_address_options_prev = show_ip_address_options; + show_ip_address_options = true; - if (changeProAdhocServer == "IP address") + var.key = "ppsspp_change_pro_ad_hoc_server_address"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && strcmp(var.value, "IP address")) + show_ip_address_options = false; + + if (show_ip_address_options != show_ip_address_options_prev) { - g_Config.proAdhocServer = ""; - for (int i = 0;;) + option_display.visible = show_ip_address_options; + for (int i = 0; i < 12; i++) { - int addressPt = 0; - ppsspp_pro_ad_hoc_ipv4[i].Show(true); - ppsspp_pro_ad_hoc_ipv4[i].Update(&addressPt); - g_Config.proAdhocServer += static_cast('0' + addressPt); - - if (++i == 12) - break; - - if (i % 3 == 0) - g_Config.proAdhocServer += '.'; + char key[64] = {0}; + option_display.key = key; + snprintf(key, sizeof(key), "ppsspp_pro_ad_hoc_server_address%02d", i + 1); + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); } - } - else - { - g_Config.proAdhocServer = changeProAdhocServer; - - for (int i = 0; i < 12; ++i) - ppsspp_pro_ad_hoc_ipv4[i].Show(false); - } - - if (ppsspp_enable_upnp.Update(&g_Config.bEnableUPnP)) updated = true; + } - ppsspp_upnp_use_original_port.Show(g_Config.bEnableUPnP); + // Show/hide 'UPnP Use Original Port' option + bool show_upnp_port_option_prev = show_upnp_port_option; + show_upnp_port_option = true; - bool detectVsyncSwapIntervalOptShownLast = detectVsyncSwapIntervalOptShown; - bool autoFrameSkip = false; - int frameSkip = 0; - bool renderDuplicateFrames = false; + var.key = "ppsspp_enable_upnp"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "disabled")) + show_upnp_port_option = false; - ppsspp_auto_frameskip.Update(&autoFrameSkip); - ppsspp_frameskip.Update(&frameSkip); - ppsspp_frame_duplication.Update(&renderDuplicateFrames); - - detectVsyncSwapIntervalOptShown = - !autoFrameSkip && - (frameSkip == 0) && - !renderDuplicateFrames; - - if (detectVsyncSwapIntervalOptShown != detectVsyncSwapIntervalOptShownLast) + if (show_upnp_port_option != show_upnp_port_option_prev) { - ppsspp_detect_vsync_swap_interval.Show(detectVsyncSwapIntervalOptShown); + option_display.visible = show_upnp_port_option; + option_display.key = "ppsspp_upnp_use_original_port"; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + updated = true; + } + + // Show/hide 'Detect Frame Rate Changes' option + bool show_detect_frame_rate_option_prev = show_detect_frame_rate_option; + int frameskip = 0; + bool auto_frameskip = false; + bool dupe_frames = false; + show_detect_frame_rate_option = true; + + var.key = "ppsspp_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && strcmp(var.value, "disabled")) + frameskip = atoi(var.value); + var.key = "ppsspp_auto_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "enabled")) + auto_frameskip = true; + var.key = "ppsspp_frame_duplication"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "enabled")) + dupe_frames = true; + + show_detect_frame_rate_option = (frameskip == 0) && !auto_frameskip && !dupe_frames; + if (show_detect_frame_rate_option != show_detect_frame_rate_option_prev) + { + option_display.visible = show_detect_frame_rate_option; + option_display.key = "ppsspp_detect_vsync_swap_interval"; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); updated = true; } @@ -671,59 +512,10 @@ void retro_set_environment(retro_environment_t cb) { environ_cb = cb; + libretro_set_core_options(environ_cb, &libretro_supports_option_categories); struct retro_core_options_update_display_callback update_display_cb; update_display_cb.callback = set_variable_visibility; environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK, &update_display_cb); - - std::vector vars; - vars.push_back(ppsspp_internal_resolution.GetOptions()); - vars.push_back(ppsspp_cpu_core.GetOptions()); - vars.push_back(ppsspp_locked_cpu_speed.GetOptions()); - vars.push_back(ppsspp_language.GetOptions()); - vars.push_back(ppsspp_button_preference.GetOptions()); - vars.push_back(ppsspp_rendering_mode.GetOptions()); - vars.push_back(ppsspp_gpu_hardware_transform.GetOptions()); - vars.push_back(ppsspp_texture_anisotropic_filtering.GetOptions()); - vars.push_back(ppsspp_spline_quality.GetOptions()); - vars.push_back(ppsspp_auto_frameskip.GetOptions()); - vars.push_back(ppsspp_frameskip.GetOptions()); - vars.push_back(ppsspp_frameskiptype.GetOptions()); - vars.push_back(ppsspp_frame_duplication.GetOptions()); - vars.push_back(ppsspp_detect_vsync_swap_interval.GetOptions()); - vars.push_back(ppsspp_vertex_cache.GetOptions()); - vars.push_back(ppsspp_fast_memory.GetOptions()); - vars.push_back(ppsspp_block_transfer_gpu.GetOptions()); - vars.push_back(ppsspp_inflight_frames.GetOptions()); - vars.push_back(ppsspp_software_skinning.GetOptions()); - vars.push_back(ppsspp_lazy_texture_caching.GetOptions()); - vars.push_back(ppsspp_retain_changed_textures.GetOptions()); - vars.push_back(ppsspp_force_lag_sync.GetOptions()); - vars.push_back(ppsspp_lower_resolution_for_effects.GetOptions()); - vars.push_back(ppsspp_texture_scaling_level.GetOptions()); - vars.push_back(ppsspp_texture_scaling_type.GetOptions()); - vars.push_back(ppsspp_texture_shader.GetOptions()); - vars.push_back(ppsspp_texture_filtering.GetOptions()); - vars.push_back(ppsspp_texture_deposterize.GetOptions()); - vars.push_back(ppsspp_texture_replacement.GetOptions()); - vars.push_back(ppsspp_io_timing_method.GetOptions()); - vars.push_back(ppsspp_ignore_bad_memory_access.GetOptions()); - vars.push_back(ppsspp_cheats.GetOptions()); - vars.push_back(ppsspp_enable_wlan.GetOptions()); - for (int i = 0; i < 12; ++i) - vars.push_back(ppsspp_change_mac_address[i].GetOptions()); - vars.push_back(ppsspp_wlan_channel.GetOptions()); - vars.push_back(ppsspp_enable_builtin_pro_ad_hoc_server.GetOptions()); - vars.push_back(ppsspp_change_pro_ad_hoc_server_address.GetOptions()); - for (int i = 0; i < 12; ++i) - vars.push_back(ppsspp_pro_ad_hoc_ipv4[i].GetOptions()); - vars.push_back(ppsspp_enable_upnp.GetOptions()); - vars.push_back(ppsspp_upnp_use_original_port.GetOptions()); - vars.push_back(ppsspp_port_offset.GetOptions()); - vars.push_back(ppsspp_minimum_timeout.GetOptions()); - vars.push_back(ppsspp_forced_first_connect.GetOptions()); - vars.push_back({}); - - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars.data()); } static int get_language_auto(void) @@ -803,46 +595,528 @@ static void check_variables(CoreParameter &coreParam) && !updated) return; - ppsspp_button_preference.Update(&g_Config.iButtonPreference); - ppsspp_fast_memory.Update(&g_Config.bFastMemory); - ppsspp_vertex_cache.Update(&g_Config.bVertexCache); - ppsspp_gpu_hardware_transform.Update(&g_Config.bHardwareTransform); - ppsspp_frameskip.Update(&g_Config.iFrameSkip); - ppsspp_frameskiptype.Update(&g_Config.iFrameSkipType); - ppsspp_auto_frameskip.Update(&g_Config.bAutoFrameSkip); - ppsspp_block_transfer_gpu.Update(&g_Config.bBlockTransferGPU); - ppsspp_texture_filtering.Update(&g_Config.iTexFiltering); - ppsspp_texture_anisotropic_filtering.Update(&g_Config.iAnisotropyLevel); - ppsspp_texture_deposterize.Update(&g_Config.bTexDeposterize); - ppsspp_texture_replacement.Update(&g_Config.bReplaceTextures); - ppsspp_cheats.Update(&g_Config.bEnableCheats); - ppsspp_locked_cpu_speed.Update(&g_Config.iLockedCPUSpeed); - ppsspp_rendering_mode.Update(&g_Config.iRenderingMode); - ppsspp_cpu_core.Update((CPUCore *)&g_Config.iCpuCore); - ppsspp_io_timing_method.Update((IOTimingMethods *)&g_Config.iIOTimingMethod); - ppsspp_lower_resolution_for_effects.Update(&g_Config.iBloomHack); - ppsspp_frame_duplication.Update(&g_Config.bRenderDuplicateFrames); - ppsspp_detect_vsync_swap_interval.Update(&detectVsyncSwapInterval); - ppsspp_software_skinning.Update(&g_Config.bSoftwareSkinning); - ppsspp_ignore_bad_memory_access.Update(&g_Config.bIgnoreBadMemAccess); - ppsspp_lazy_texture_caching.Update(&g_Config.bTextureBackoffCache); - ppsspp_retain_changed_textures.Update(&g_Config.bTextureSecondaryCache); - ppsspp_force_lag_sync.Update(&g_Config.bForceLagSync); - ppsspp_spline_quality.Update(&g_Config.iSplineBezierQuality); - ppsspp_inflight_frames.Update(&g_Config.iInflightFrames); - const bool do_scaling_type_update = ppsspp_texture_scaling_type.Update(&g_Config.iTexScalingType); - const bool do_scaling_level_update = ppsspp_texture_scaling_level.Update(&g_Config.iTexScalingLevel); - const bool do_texture_shader_update = ppsspp_texture_shader.Update(&g_Config.sTextureShaderName); + struct retro_variable var = {0}; + std::string sTextureShaderName_prev; + int iInternalResolution_prev; + int iTexScalingType_prev; + int iTexScalingLevel_prev; + int iMultiSampleLevel_prev; - g_Config.bTexHardwareScaling = "Off" != g_Config.sTextureShaderName; - - if (gpu && (do_scaling_type_update || do_scaling_level_update || do_texture_shader_update)) + var.key = "ppsspp_language"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - gpu->ClearCacheNextFrame(); - gpu->Resized(); + if (!strcmp(var.value, "Automatic")) + g_Config.iLanguage = -1; + else if (!strcmp(var.value, "English")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; + else if (!strcmp(var.value, "Japanese")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_JAPANESE; + else if (!strcmp(var.value, "French")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_FRENCH; + else if (!strcmp(var.value, "Spanish")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_SPANISH; + else if (!strcmp(var.value, "German")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_GERMAN; + else if (!strcmp(var.value, "Italian")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ITALIAN; + else if (!strcmp(var.value, "Dutch")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_DUTCH; + else if (!strcmp(var.value, "Portuguese")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE; + else if (!strcmp(var.value, "Russian")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN; + else if (!strcmp(var.value, "Korean")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_KOREAN; + else if (!strcmp(var.value, "Chinese Traditional")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL; + else if (!strcmp(var.value, "Chinese Simplified")) + g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED; + } + + var.key = "ppsspp_cpu_core"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "JIT")) + g_Config.iCpuCore = (int)CPUCore::JIT; + else if (!strcmp(var.value, "IR JIT")) + g_Config.iCpuCore = (int)CPUCore::IR_JIT; + else if (!strcmp(var.value, "Interpreter")) + g_Config.iCpuCore = (int)CPUCore::INTERPRETER; + } + + var.key = "ppsspp_fast_memory"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bFastMemory = false; + else + g_Config.bFastMemory = true; + } + + var.key = "ppsspp_ignore_bad_memory_access"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bIgnoreBadMemAccess = false; + else + g_Config.bIgnoreBadMemAccess = true; + } + + var.key = "ppsspp_io_timing_method"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Fast")) + g_Config.iIOTimingMethod = IOTIMING_FAST; + else if (!strcmp(var.value, "Host")) + g_Config.iIOTimingMethod = IOTIMING_HOST; + else if (!strcmp(var.value, "Simulate UMD delays")) + g_Config.iIOTimingMethod = IOTIMING_REALISTIC; + } + + var.key = "ppsspp_force_lag_sync"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bForceLagSync = false; + else + g_Config.bForceLagSync = true; + } + + var.key = "ppsspp_locked_cpu_speed"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iLockedCPUSpeed = atoi(var.value); + + var.key = "ppsspp_cache_iso"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bCacheFullIsoInRam = false; + else + g_Config.bCacheFullIsoInRam = true; + } + + var.key = "ppsspp_cheats"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableCheats = false; + else + g_Config.bEnableCheats = true; + } + + var.key = "ppsspp_psp_model"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "psp_1000")) + g_Config.iPSPModel = PSP_MODEL_FAT; + else if (!strcmp(var.value, "psp_2000_3000")) + g_Config.iPSPModel = PSP_MODEL_SLIM; + } + + var.key = "ppsspp_button_preference"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Cross")) + g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS; + else if (!strcmp(var.value, "Circle")) + g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CIRCLE; + } + + var.key = "ppsspp_internal_resolution"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iInternalResolution_prev = g_Config.iInternalResolution; + + if (!strcmp(var.value, "480x272")) + g_Config.iInternalResolution = 1; + else if (!strcmp(var.value, "960x544")) + g_Config.iInternalResolution = 2; + else if (!strcmp(var.value, "1440x816")) + g_Config.iInternalResolution = 3; + else if (!strcmp(var.value, "1920x1088")) + g_Config.iInternalResolution = 4; + else if (!strcmp(var.value, "2400x1360")) + g_Config.iInternalResolution = 5; + else if (!strcmp(var.value, "2880x1632")) + g_Config.iInternalResolution = 6; + else if (!strcmp(var.value, "3360x1904")) + g_Config.iInternalResolution = 7; + else if (!strcmp(var.value, "3840x2176")) + g_Config.iInternalResolution = 8; + else if (!strcmp(var.value, "4320x2448")) + g_Config.iInternalResolution = 9; + else if (!strcmp(var.value, "4800x2720")) + g_Config.iInternalResolution = 10; + } + + var.key = "ppsspp_mulitsample_level"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iMultiSampleLevel_prev = g_Config.iMultiSampleLevel; + + if (!strcmp(var.value, "Disabled")) + g_Config.iMultiSampleLevel = 0; + else if (!strcmp(var.value, "x2")) + g_Config.iMultiSampleLevel = 1; + else if (!strcmp(var.value, "x4")) + g_Config.iMultiSampleLevel = 2; + else if (!strcmp(var.value, "x8")) + g_Config.iMultiSampleLevel = 3; + } + + var.key = "ppsspp_skip_buffer_effects"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSkipBufferEffects = false; + else + g_Config.bSkipBufferEffects = true; + } + + var.key = "ppsspp_skip_gpu_readbacks"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSkipGPUReadbacks = false; + else + g_Config.bSkipGPUReadbacks = true; + } + + var.key = "ppsspp_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iFrameSkip = atoi(var.value); + + var.key = "ppsspp_frameskiptype"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Number of frames")) + g_Config.iFrameSkipType = 0; + else if (!strcmp(var.value, "Percent of FPS")) + g_Config.iFrameSkipType = 1; + } + + var.key = "ppsspp_auto_frameskip"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bAutoFrameSkip = false; + else + g_Config.bAutoFrameSkip = true; + } + + var.key = "ppsspp_frame_duplication"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bRenderDuplicateFrames = false; + else + g_Config.bRenderDuplicateFrames = true; + } + + var.key = "ppsspp_detect_vsync_swap_interval"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + detectVsyncSwapInterval = false; + else + detectVsyncSwapInterval = true; + } + + var.key = "ppsspp_inflight_frames"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "No buffer")) + g_Config.iInflightFrames = 0; + else if (!strcmp(var.value, "Up to 1")) + g_Config.iInflightFrames = 1; + else if (!strcmp(var.value, "Up to 2")) + g_Config.iInflightFrames = 2; + } + + var.key = "ppsspp_gpu_hardware_transform"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bHardwareTransform = false; + else + g_Config.bHardwareTransform = true; + } + + var.key = "ppsspp_software_skinning"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSoftwareSkinning = false; + else + g_Config.bSoftwareSkinning = true; + } + + var.key = "ppsspp_vertex_cache"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bVertexCache = false; + else + g_Config.bVertexCache = true; + } + + var.key = "ppsspp_lazy_texture_caching"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bTextureBackoffCache = false; + else + g_Config.bTextureBackoffCache = true; + } + + var.key = "ppsspp_spline_quality"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Low")) + g_Config.iSplineBezierQuality = 0; + else if (!strcmp(var.value, "Medium")) + g_Config.iSplineBezierQuality = 1; + else if (!strcmp(var.value, "High")) + g_Config.iSplineBezierQuality = 2; + } + + var.key = "ppsspp_hardware_tesselation"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bHardwareTessellation = false; + else + g_Config.bHardwareTessellation = true; + } + + var.key = "ppsspp_lower_resolution_for_effects"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.iBloomHack = 0; + else if (!strcmp(var.value, "Safe")) + g_Config.iBloomHack = 1; + else if (!strcmp(var.value, "Balanced")) + g_Config.iBloomHack = 2; + else if (!strcmp(var.value, "Aggressive")) + g_Config.iBloomHack = 3; + } + + var.key = "ppsspp_texture_scaling_type"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iTexScalingType_prev = g_Config.iTexScalingType; + + if (!strcmp(var.value, "xbrz")) + g_Config.iTexScalingType = TextureScalerCommon::XBRZ; + else if (!strcmp(var.value, "hybrid")) + g_Config.iTexScalingType = TextureScalerCommon::HYBRID; + else if (!strcmp(var.value, "bicubic")) + g_Config.iTexScalingType = TextureScalerCommon::BICUBIC; + else if (!strcmp(var.value, "hybrid_bicubic")) + g_Config.iTexScalingType = TextureScalerCommon::HYBRID_BICUBIC; + } + + var.key = "ppsspp_texture_scaling_level"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + iTexScalingLevel_prev = g_Config.iTexScalingLevel; + + if (!strcmp(var.value, "disabled")) + g_Config.iTexScalingLevel = 1; + else if (!strcmp(var.value, "2x")) + g_Config.iTexScalingLevel = 2; + else if (!strcmp(var.value, "3x")) + g_Config.iTexScalingLevel = 3; + else if (!strcmp(var.value, "4x")) + g_Config.iTexScalingLevel = 4; + else if (!strcmp(var.value, "5x")) + g_Config.iTexScalingLevel = 5; + } + + var.key = "ppsspp_texture_deposterize"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bTexDeposterize = false; + else + g_Config.bTexDeposterize = true; + } + + var.key = "ppsspp_texture_shader"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + sTextureShaderName_prev = g_Config.sTextureShaderName; + + if (!strcmp(var.value, "disabled")) + g_Config.sTextureShaderName = "Off"; + else if (!strcmp(var.value, "2xBRZ")) + g_Config.sTextureShaderName = "Tex2xBRZ"; + else if (!strcmp(var.value, "4xBRZ")) + g_Config.sTextureShaderName = "Tex4xBRZ"; + else if (!strcmp(var.value, "MMPX")) + g_Config.sTextureShaderName = "TexMMPX"; + } + + var.key = "ppsspp_texture_anisotropic_filtering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.iAnisotropyLevel = 0; + else if (!strcmp(var.value, "2x")) + g_Config.iAnisotropyLevel = 1; + else if (!strcmp(var.value, "4x")) + g_Config.iAnisotropyLevel = 2; + else if (!strcmp(var.value, "8x")) + g_Config.iAnisotropyLevel = 3; + else if (!strcmp(var.value, "16x")) + g_Config.iAnisotropyLevel = 4; + } + + var.key = "ppsspp_texture_filtering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "Auto")) + g_Config.iTexFiltering = 1; + else if (!strcmp(var.value, "Nearest")) + g_Config.iTexFiltering = 2; + else if (!strcmp(var.value, "Linear")) + g_Config.iTexFiltering = 3; + else if (!strcmp(var.value, "Auto max quality")) + g_Config.iTexFiltering = 4; + } + + var.key = "ppsspp_texture_replacement"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bReplaceTextures = false; + else + g_Config.bReplaceTextures = true; + } + + var.key = "ppsspp_enable_wlan"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableWlan = false; + else + g_Config.bEnableWlan = true; + } + + var.key = "ppsspp_wlan_channel"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iWlanAdhocChannel = atoi(var.value); + + var.key = "ppsspp_enable_builtin_pro_ad_hoc_server"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableAdhocServer = false; + else + g_Config.bEnableAdhocServer = true; + } + + var.key = "ppsspp_change_pro_ad_hoc_server_address"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + changeProAdhocServer = var.value; + + var.key = "ppsspp_enable_upnp"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bEnableUPnP = false; + else + g_Config.bEnableUPnP = true; + } + + var.key = "ppsspp_upnp_use_original_port"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bUPnPUseOriginalPort = false; + else + g_Config.bUPnPUseOriginalPort = true; + } + + var.key = "ppsspp_port_offset"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iPortOffset = atoi(var.value); + + var.key = "ppsspp_minimum_timeout"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + g_Config.iMinTimeout = atoi(var.value); + + var.key = "ppsspp_forced_first_connect"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bForcedFirstConnect = false; + else + g_Config.bForcedFirstConnect = true; + } + + std::string ppsspp_change_mac_address[12]; + int ppsspp_pro_ad_hoc_ipv4[12]; + char key[64] = {0}; + var.key = key; + g_Config.sMACAddress = ""; + g_Config.proAdhocServer = ""; + for (int i = 0; i < 12; i++) + { + snprintf(key, sizeof(key), "ppsspp_change_mac_address%02d", i + 1); + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + ppsspp_change_mac_address[i] = var.value; + + if (i && i % 2 == 0) + g_Config.sMACAddress += ":"; + + g_Config.sMACAddress += ppsspp_change_mac_address[i]; + } + + snprintf(key, sizeof(key), "ppsspp_pro_ad_hoc_server_address%02d", i + 1); + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + ppsspp_pro_ad_hoc_ipv4[i] = atoi(var.value); + } + + if (g_Config.sMACAddress == "00:00:00:00:00:00") + { + g_Config.sMACAddress = CreateRandMAC(); + + for (int i = 0; i < 12; i++) + { + snprintf(key, sizeof(key), "ppsspp_change_mac_address%02d", i + 1); + std::string digit = {g_Config.sMACAddress[i + i / 2]}; + var.value = digit.c_str(); + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, &var); + } + } + + if (changeProAdhocServer == "IP address") + { + g_Config.proAdhocServer = ""; + for (int i = 0; i < 12; i++) + { + if (i && i % 3 == 0) + g_Config.proAdhocServer += '.'; + + int addressPt = ppsspp_pro_ad_hoc_ipv4[i]; + g_Config.proAdhocServer += static_cast('0' + addressPt); + } + } + else + g_Config.proAdhocServer = changeProAdhocServer; + + g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off"; + + if (gpu && (g_Config.iTexScalingType != iTexScalingType_prev + || g_Config.iTexScalingLevel != iTexScalingLevel_prev + || g_Config.sTextureShaderName != sTextureShaderName_prev)) + { + gpu->NotifyConfigChanged(); } - ppsspp_language.Update(&g_Config.iLanguage); if (g_Config.iLanguage < 0) g_Config.iLanguage = get_language_auto(); @@ -864,7 +1138,7 @@ static void check_variables(CoreParameter &coreParam) updateAvInfo = true; } - if (ppsspp_internal_resolution.Update(&g_Config.iInternalResolution) && !PSP_IsInited()) + if (g_Config.iInternalResolution != iInternalResolution_prev && !PSP_IsInited()) { coreParam.pixelWidth = coreParam.renderWidth = g_Config.iInternalResolution * 480; coreParam.pixelHeight = coreParam.renderHeight = g_Config.iInternalResolution * 272; @@ -875,7 +1149,15 @@ static void check_variables(CoreParameter &coreParam) retro_get_system_av_info(&avInfo); environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo); updateAvInfo = false; - gpu->Resized(); + gpu->NotifyDisplayResized(); + } + } + + if (g_Config.iMultiSampleLevel != iMultiSampleLevel_prev && PSP_IsInited()) + { + if (gpu) + { + gpu->NotifyRenderResized(); } } @@ -889,40 +1171,6 @@ static void check_variables(CoreParameter &coreParam) bool isFastForwarding = environ_cb(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &isFastForwarding); coreParam.fastForward = isFastForwarding; - ppsspp_enable_wlan.Update(&g_Config.bEnableWlan); - ppsspp_wlan_channel.Update(&g_Config.iWlanAdhocChannel); - ppsspp_enable_builtin_pro_ad_hoc_server.Update(&g_Config.bEnableAdhocServer); - - ppsspp_upnp_use_original_port.Update(&g_Config.bUPnPUseOriginalPort); - ppsspp_port_offset.Update(&g_Config.iPortOffset); - ppsspp_minimum_timeout.Update(&g_Config.iMinTimeout); - ppsspp_forced_first_connect.Update(&g_Config.bForcedFirstConnect); - - g_Config.sMACAddress = ""; - for (int i = 0; i < 12;) - { - std::string digit; - ppsspp_change_mac_address[i].Update(&digit); - g_Config.sMACAddress += digit; - - if (++i == 12) - break; - - if (i % 2 == 0) - g_Config.sMACAddress += ":"; - } - - if (g_Config.sMACAddress == "00:00:00:00:00:00") - { - g_Config.sMACAddress = CreateRandMAC(); - - for (int i = 0; i < 12; ++i) - { - std::string digit = {g_Config.sMACAddress[i + i / 2]}; - ppsspp_change_mac_address[i].Set(digit.c_str()); - } - } - set_variable_visibility(); } @@ -1018,6 +1266,7 @@ void retro_deinit(void) host = nullptr; libretro_supports_bitmasks = false; + libretro_supports_option_categories = false; VsyncSwapIntervalReset(); AudioBufferDeinit(); @@ -1167,6 +1416,9 @@ bool retro_load_game(const struct retro_game_info *game) useEmuThread = ctx->GetGPUCore() == GPUCORE_GLES; + // default to interpreter to allow startup in platforms w/o JIT capability + g_Config.iCpuCore = (int)CPUCore::INTERPRETER; + CoreParameter coreParam = {}; coreParam.enableSound = true; coreParam.fileToStart = Path(std::string(game->path)); @@ -1176,9 +1428,11 @@ bool retro_load_game(const struct retro_game_info *game) coreParam.headLess = true; coreParam.graphicsContext = ctx; coreParam.gpuCore = ctx->GetGPUCore(); - coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; check_variables(coreParam); + // set cpuCore from libretro setting variable + coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; + std::string error_string; if (!PSP_InitStart(coreParam, &error_string)) { @@ -1417,9 +1671,86 @@ size_t retro_get_memory_size(unsigned id) return 0; } -void retro_cheat_reset(void) {} +void retro_cheat_reset(void) { + // Init Cheat Engine + CWCheatEngine *cheatEngine = new CWCheatEngine(g_paramSFO.GetDiscID()); + Path file=cheatEngine->CheatFilename(); -void retro_cheat_set(unsigned index, bool enabled, const char *code) { } + // Output cheats to cheat file + std::ofstream outFile; + outFile.open(file.c_str()); + outFile << "_S " << g_paramSFO.GetDiscID() << std::endl; + outFile.close(); + + g_Config.bReloadCheats = true; + + // Parse and Run the Cheats + cheatEngine->ParseCheats(); + if (cheatEngine->HasCheats()) { + cheatEngine->Run(); + } + +} + +void retro_cheat_set(unsigned index, bool enabled, const char *code) { + // Initialize Cheat Engine + CWCheatEngine *cheatEngine = new CWCheatEngine(g_paramSFO.GetDiscID()); + cheatEngine->CreateCheatFile(); + Path file=cheatEngine->CheatFilename(); + + // Read cheats file + std::vector cheats; + std::ifstream cheat_content(file.c_str()); + std::stringstream buffer; + buffer << cheat_content.rdbuf(); + std::string existing_cheats=ReplaceAll(buffer.str(), std::string("\n_C"), std::string("|")); + SplitString(existing_cheats, '|', cheats); + + // Generate Cheat String + std::stringstream cheat(""); + cheat << (enabled ? "1 " : "0 ") << index << std::endl; + std::string code_str(code); + std::vector codes; + code_str=ReplaceAll(code_str, std::string(" "), std::string("+")); + SplitString(code_str, '+', codes); + int part=0; + for (int i=0; i < codes.size(); i++) { + if (codes[i].size() <= 2) { + // _L _M ..etc + // Assume _L + } else if (part == 0) { + cheat << "_L " << codes[i] << " "; + part++; + } else { + cheat << codes[i] << std::endl; + part=0; + } + } + + // Add or Replace the Cheat + if (index + 1 < cheats.size()) { + cheats[index + 1]=cheat.str(); + } else { + cheats.push_back(cheat.str()); + } + + // Output cheats to cheat file + std::ofstream outFile; + outFile.open(file.c_str()); + outFile << "_S " << g_paramSFO.GetDiscID() << std::endl; + for (int i=1; i < cheats.size(); i++) { + outFile << "_C" << cheats[i] << std::endl; + } + outFile.close(); + + g_Config.bReloadCheats = true; + + // Parse and Run the Cheats + cheatEngine->ParseCheats(); + if (cheatEngine->HasCheats()) { + cheatEngine->Run(); + } +} int System_GetPropertyInt(SystemProperty prop) { diff --git a/libretro/libretro.h b/libretro/libretro.h index 2f17483701..bb114aed35 100644 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -283,6 +283,12 @@ enum retro_language RETRO_LANGUAGE_HEBREW = 21, RETRO_LANGUAGE_ASTURIAN = 22, RETRO_LANGUAGE_FINNISH = 23, + RETRO_LANGUAGE_INDONESIAN = 24, + RETRO_LANGUAGE_SWEDISH = 25, + RETRO_LANGUAGE_UKRAINIAN = 26, + RETRO_LANGUAGE_CZECH = 27, + RETRO_LANGUAGE_CATALAN_VALENCIA = 28, + RETRO_LANGUAGE_CATALAN = 29, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -1753,6 +1759,12 @@ enum retro_mod * the frontend is attempting to call retro_run(). */ +#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* int * -- + * Tells the core about the context the frontend is asking for savestate. + * (see enum retro_savestate_context) + */ + /* VFS functionality */ /* File paths: @@ -2990,6 +3002,35 @@ enum retro_pixel_format RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX }; +enum retro_savestate_context +{ + /* Standard savestate written to disk. */ + RETRO_SAVESTATE_CONTEXT_NORMAL = 0, + + /* Savestate where you are guaranteed that the same instance will load the save state. + * You can store internal pointers to code or data. + * It's still a full serialization and deserialization, and could be loaded or saved at any time. + * It won't be written to disk or sent over the network. + */ + RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1, + + /* Savestate where you are guaranteed that the same emulator binary will load that savestate. + * You can skip anything that would slow down saving or loading state but you can not store internal pointers. + * It won't be written to disk or sent over the network. + * Example: "Second Instance" runahead + */ + RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY = 2, + + /* Savestate used within a rollback netplay feature. + * You should skip anything that would unnecessarily increase bandwidth usage. + * It won't be written to disk but it will be sent over the network. + */ + RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY = 3, + + /* Ensure sizeof() == sizeof(int). */ + RETRO_SAVESTATE_CONTEXT_UNKNOWN = INT_MAX +}; + struct retro_message { const char *msg; /* Message to be displayed. */ @@ -3461,6 +3502,10 @@ struct retro_core_option_definition const char *default_value; }; +#ifdef __PS3__ +#undef local +#endif + struct retro_core_options_intl { /* Pointer to an array of retro_core_option_definition structs diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h new file mode 100644 index 0000000000..ede76d29e2 --- /dev/null +++ b/libretro/libretro_core_options.h @@ -0,0 +1,1361 @@ +#ifndef LIBRETRO_CORE_OPTIONS_H__ +#define LIBRETRO_CORE_OPTIONS_H__ + +#include +#include + +#include "libretro.h" +#include "retro_inline.h" + +#ifndef HAVE_NO_LANGEXTRA +#include "libretro_core_options_intl.h" +#endif + +#define BOOL_OPTIONS \ +{ \ + { "disabled", NULL }, \ + { "enabled", NULL }, \ + { NULL, NULL }, \ +} + +#define MAC_ADDRESS_OPTIONS \ +{ \ + { "0", NULL }, \ + { "1", NULL }, \ + { "2", NULL }, \ + { "3", NULL }, \ + { "4", NULL }, \ + { "5", NULL }, \ + { "6", NULL }, \ + { "7", NULL }, \ + { "8", NULL }, \ + { "9", NULL }, \ + { "a", NULL }, \ + { "b", NULL }, \ + { "c", NULL }, \ + { "d", NULL }, \ + { "e", NULL }, \ + { "f", NULL }, \ + { NULL, NULL }, \ +} + +#define IP_ADDRESS_OPTIONS \ +{ \ + { "0", NULL }, \ + { "1", NULL }, \ + { "2", NULL }, \ + { "3", NULL }, \ + { "4", NULL }, \ + { "5", NULL }, \ + { "6", NULL }, \ + { "7", NULL }, \ + { "8", NULL }, \ + { "9", NULL }, \ + { NULL, NULL }, \ +} + +/* + ******************************** + * VERSION: 2.0 + ******************************** + * + * - 2.0: Add support for core options v2 interface + * - 1.3: Move translations to libretro_core_options_intl.h + * - libretro_core_options_intl.h includes BOM and utf-8 + * fix for MSVC 2010-2013 + * - Added HAVE_NO_LANGEXTRA flag to disable translations + * on platforms/compilers without BOM support + * - 1.2: Use core options v1 interface when + * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1 + * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1) + * - 1.1: Support generation of core options v0 retro_core_option_value + * arrays containing options with a single value + * - 1.0: First commit +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ******************************** + * Core Option Definitions + ******************************** +*/ + +/* RETRO_LANGUAGE_ENGLISH */ + +/* Default language: + * - All other languages must include the same keys and values + * - Will be used as a fallback in the event that frontend language + * is not available + * - Will be used as a fallback for any missing entries in + * frontend language definition */ + +struct retro_core_option_v2_category option_cats_us[] = { + { + "system", + "System", + "Configure system options." + }, + { + "video", + "Video", + "Configure video options." + }, + { + "network", + "Network", + "Configure network options." + }, + { NULL, NULL, NULL }, +}; + +struct retro_core_option_v2_definition option_defs_us[] = { + { + "ppsspp_language", + "Language", + NULL, + "Choose language, 'Automatic' will use the frontend language.", + NULL, + "system", + { + { "Automatic", NULL }, + { "English", NULL }, + { "Japanese", NULL }, + { "French", NULL }, + { "Spanish", NULL }, + { "German", NULL }, + { "Italian", NULL }, + { "Dutch", NULL }, + { "Portuguese", NULL }, + { "Russian", NULL }, + { "Korean", NULL }, + { "Chinese Traditional", NULL }, + { "Chinese Simplified", NULL }, + { NULL, NULL }, + }, + "Automatic" + }, + { + "ppsspp_cpu_core", + "CPU Core", + NULL, + NULL, + NULL, + "system", + { + { "JIT", "Dynarec (JIT)" }, + { "IR JIT", "IR Interpreter" }, + { "Interpreter", NULL }, + { NULL, NULL }, + }, + "JIT" + }, + { + "ppsspp_fast_memory", + "Fast Memory", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_ignore_bad_memory_access", + "Ignore Bad Memory Accesses", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_io_timing_method", + "I/O Timing Method", + NULL, + NULL, + NULL, + "system", + { + { "Fast", NULL }, + { "Host", NULL }, + { "Simulate UMD delays", NULL }, + { NULL, NULL }, + }, + "Fast" + }, + { + "ppsspp_force_lag_sync", + "Force Real Clock Sync (Slower, less lag)", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_locked_cpu_speed", + "Locked CPU Speed", + NULL, + NULL, + NULL, + "system", + { + { "disabled", NULL }, + { "222MHz", NULL }, + { "266MHz", NULL }, + { "333MHz", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_cache_iso", + "Cache Full ISO in RAM", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_cheats", + "Internal Cheats Support", + NULL, + NULL, + NULL, + "system", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_psp_model", + "PSP Model", + NULL, + NULL, + NULL, + "system", + { + { "psp_1000", "PSP-1000" }, + { "psp_2000_3000", "PSP-2000/3000" }, + { NULL, NULL }, + }, + "psp_2000_3000" + }, + { + "ppsspp_button_preference", + "Confirmation Button", + NULL, + NULL, + NULL, + "system", + { + { "Cross", NULL }, + { "Circle", NULL }, + { NULL, NULL }, + }, + "Cross" + }, + { + "ppsspp_internal_resolution", + "Internal Resolution (Restart)", + NULL, + NULL, + NULL, + "video", + { + { "480x272", NULL }, + { "960x544", NULL }, + { "1440x816", NULL }, + { "1920x1088", NULL }, + { "2400x1360", NULL }, + { "2880x1632", NULL }, + { "3360x1904", NULL }, + { "3840x2176", NULL }, + { "4320x2448", NULL }, + { "4800x2720", NULL }, + { NULL, NULL }, + }, + "480x272" + }, + { + "ppsspp_mulitsample_level", + "MSAA Antialiasing (Vulkan Only)", + NULL, + NULL, + NULL, + "video", + { + {"Disabled", NULL}, + {"x2", NULL}, + {"x4", NULL}, + {"x8", NULL}, + {NULL, NULL} + }, + "Disabled" + }, + { + "ppsspp_skip_buffer_effects", + "Skip Buffer Effects", + NULL, + "Faster, but may cause major rendering issues.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_skip_gpu_readbacks", + "Skip GPU Readbacks", + NULL, + "Some games require GPU readbacks, so be careful.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_frameskip", + "Frameskip", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "1", NULL }, + { "2", NULL }, + { "3", NULL }, + { "4", NULL }, + { "5", NULL }, + { "6", NULL }, + { "7", NULL }, + { "8", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_frameskiptype", + "Frameskip Type", + NULL, + NULL, + NULL, + "video", + { + { "Number of frames", NULL }, + { "Percent of FPS", NULL }, + { NULL, NULL }, + }, + "Number of frames" + }, + { + "ppsspp_auto_frameskip", + "Auto Frameskip", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_frame_duplication", + "Duplicate Frames in 30 Hz Games", + NULL, + "Can make framerate smoother in games that run at lower framerates.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_detect_vsync_swap_interval", + "Detect Frame Rate Changes (Notify frontend)", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_inflight_frames", + "Buffered Frames (GL/Vulkan only, slower, less lag, restart)", + NULL, + NULL, + NULL, + "video", + { + { "No buffer", NULL }, + { "Up to 1", NULL }, + { "Up to 2", NULL }, + { NULL, NULL }, + }, + "Up to 2" + }, + { + "ppsspp_gpu_hardware_transform", + "Hardware Transform", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_software_skinning", + "Software Skinning", + NULL, + "Combine skinned model draws on the CPU, faster in most games.", + NULL, + "video", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_vertex_cache", + "Vertex Cache", + NULL, + "Faster, but may cause temporary flicker.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_lazy_texture_caching", + "Lazy Texture Caching (Speedup)", + NULL, + "Faster, but can cause text problems in a few games.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_spline_quality", + "Spline/Bezier Curves Quality", + NULL, + "Only used by some games, controls smoothness of curves.", + NULL, + "video", + { + { "Low", NULL }, + { "Medium", NULL }, + { "High", NULL }, + { NULL, NULL }, + }, + "High" + }, + { + "ppsspp_hardware_tesselation", + "Hardware Tesselation", + NULL, + "Uses hardware to make curves.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_lower_resolution_for_effects", + "Lower Resolution for Effects", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "Safe", NULL }, + { "Balanced", NULL }, + { "Aggressive", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_texture_scaling_type", + "Texture Scaling Type", + NULL, + NULL, + NULL, + "video", + { + { "xbrz", "xBRZ" }, + { "hybrid", "Hybrid" }, + { "bicubic", "Bicubic" }, + { "hybrid_bicubic", "Hybrid + Bicubic" }, + { NULL, NULL }, + }, + "xbrz" + }, + { + "ppsspp_texture_scaling_level", + "Texture Scaling Level", + NULL, + "CPU heavy, some scaling may be delayed to avoid stutter.", + NULL, + "video", + { + { "disabled", NULL }, + { "2x", NULL }, + { "3x", NULL }, + { "4x", NULL }, + { "5x", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_texture_deposterize", + "Texture Deposterize", + NULL, + "Fixes visual banding glitches in upscaled textures.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_texture_shader", + "Texture Shader (Vulkan only, overrides 'Texture Scaling Type')", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "2xBRZ", "Tex2xBRZ" }, + { "4xBRZ", "Tex4xBRZ" }, + { "MMPX", "TexMMPX" }, + { NULL, NULL }, + }, + "disabled" + }, + { + "ppsspp_texture_anisotropic_filtering", + "Anisotropic Filtering", + NULL, + NULL, + NULL, + "video", + { + { "disabled", NULL }, + { "2x", NULL }, + { "4x", NULL }, + { "8x", NULL }, + { "16x", NULL }, + { NULL, NULL }, + }, + "16x" + }, + { + "ppsspp_texture_filtering", + "Texture Filtering", + NULL, + NULL, + NULL, + "video", + { + { "Auto", NULL }, + { "Nearest", NULL }, + { "Linear", NULL }, + { "Auto max quality", NULL }, + { NULL, NULL }, + }, + "Auto" + }, + { + "ppsspp_texture_replacement", + "Texture Replacement", + NULL, + NULL, + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_enable_wlan", + "Enable Networking/WLAN (Beta, may break games)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_change_mac_address01", + "MAC Address Pt 1: X-:--:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address02", + "MAC Address Pt 2: -X:--:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address03", + "MAC Address Pt 3: --:X-:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address04", + "MAC Address Pt 4: --:-X:--:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address05", + "MAC Address Pt 5: --:--:X-:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address06", + "MAC Address Pt 6: --:--:-X:--:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address07", + "MAC Address Pt 7: --:--:--:X-:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address08", + "MAC Address Pt 8: --:--:--:-X:--:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address09", + "MAC Address Pt 9: --:--:--:--:X-:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address10", + "MAC Address Pt 10: --:--:--:--:-X:--", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address11", + "MAC Address Pt 11: --:--:--:--:--:X-", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_change_mac_address12", + "MAC Address Pt 12: --:--:--:--:--:-X", + NULL, + NULL, + NULL, + "network", + MAC_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_wlan_channel", + "WLAN Channel", + NULL, + NULL, + NULL, + "network", + { + { "Auto", NULL }, + { "1", NULL }, + { "6", NULL }, + { "11", NULL }, + { NULL, NULL }, + }, + "Auto" + }, + { + "ppsspp_enable_builtin_pro_ad_hoc_server", + "Enable Built-in PRO Ad Hoc Server", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_change_pro_ad_hoc_server_address", + "Change PRO Ad Hoc Server IP Address ('localhost' = multiple instances)", + NULL, + NULL, + NULL, + "network", + { + { "socom.cc", NULL }, + { "psp.gameplayer.club", NULL }, + { "myneighborsushicat.com", NULL }, + { "localhost", NULL }, + { "IP address", NULL }, + { NULL, NULL }, + }, + "socom.cc" + }, + { + "ppsspp_pro_ad_hoc_server_address01", + "PRO Ad Hoc Server IP Address Pt 1: x--.---.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address02", + "PRO Ad Hoc Server IP Address Pt 2: -x-.---.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address03", + "PRO Ad Hoc Server IP Address Pt 3: --x.---.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address04", + "PRO Ad Hoc Server IP Address Pt 4: ---.x--.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address05", + "PRO Ad Hoc Server IP Address Pt 5: ---.-x-.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address06", + "PRO Ad Hoc Server IP Address Pt 6: ---.--x.---.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address07", + "PRO Ad Hoc Server IP Address Pt 7: ---.---.x--.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address08", + "PRO Ad Hoc Server IP Address Pt 8: ---.---.-x-.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address09", + "PRO Ad Hoc Server IP Address Pt 9: ---.---.--x.---", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address10", + "PRO Ad Hoc Server IP Address Pt 10: ---.---.---.x--", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address11", + "PRO Ad Hoc Server IP Address Pt 11: ---.---.---.-x-", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_pro_ad_hoc_server_address12", + "PRO Ad Hoc Server IP Address Pt 12: ---.---.---.--x", + NULL, + NULL, + NULL, + "network", + IP_ADDRESS_OPTIONS, + "0" + }, + { + "ppsspp_enable_upnp", + "Enable UPnP (Need a few seconds to detect)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_upnp_use_original_port", + "UPnP Use Original Port ('ON' = PSP compatibility)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "enabled" + }, + { + "ppsspp_port_offset", + "Port Offset ('0' = PSP compatibility)", + NULL, + NULL, + NULL, + "network", + { + { "0", NULL }, + { "1000", NULL }, + { "2000", NULL }, + { "3000", NULL }, + { "4000", NULL }, + { "5000", NULL }, + { "6000", NULL }, + { "7000", NULL }, + { "8000", NULL }, + { "9000", NULL }, + { "10000", NULL }, + { "11000", NULL }, + { "12000", NULL }, + { "13000", NULL }, + { "14000", NULL }, + { "15000", NULL }, + { "16000", NULL }, + { "17000", NULL }, + { "18000", NULL }, + { "19000", NULL }, + { "20000", NULL }, + { "31000", NULL }, + { "32000", NULL }, + { "33000", NULL }, + { "34000", NULL }, + { "35000", NULL }, + { "36000", NULL }, + { "37000", NULL }, + { "38000", NULL }, + { "39000", NULL }, + { "40000", NULL }, + { "41000", NULL }, + { "42000", NULL }, + { "43000", NULL }, + { "44000", NULL }, + { "45000", NULL }, + { "46000", NULL }, + { "47000", NULL }, + { "48000", NULL }, + { "49000", NULL }, + { "50000", NULL }, + { "51000", NULL }, + { "52000", NULL }, + { "53000", NULL }, + { "54000", NULL }, + { "55000", NULL }, + { "56000", NULL }, + { "57000", NULL }, + { "58000", NULL }, + { "59000", NULL }, + { "60000", NULL }, + { "61000", NULL }, + { "62000", NULL }, + { "63000", NULL }, + { "64000", NULL }, + { "65000", NULL }, + { NULL, NULL }, + }, + "0" + }, + { + "ppsspp_minimum_timeout", + "Minimum Timeout (Override in ms, '0' = default)", + NULL, + NULL, + NULL, + "network", + { + { "0", NULL }, + { "100", NULL }, + { "200", NULL }, + { "300", NULL }, + { "400", NULL }, + { "500", NULL }, + { "600", NULL }, + { "700", NULL }, + { "800", NULL }, + { "900", NULL }, + { "1000", NULL }, + { "1100", NULL }, + { "1200", NULL }, + { "1300", NULL }, + { "1400", NULL }, + { "1500", NULL }, + { "1600", NULL }, + { "1700", NULL }, + { "1800", NULL }, + { "1900", NULL }, + { "2000", NULL }, + { "3100", NULL }, + { "3200", NULL }, + { "3300", NULL }, + { "3400", NULL }, + { "3500", NULL }, + { "3600", NULL }, + { "3700", NULL }, + { "3800", NULL }, + { "3900", NULL }, + { "4000", NULL }, + { "4100", NULL }, + { "4200", NULL }, + { "4300", NULL }, + { "4400", NULL }, + { "4500", NULL }, + { "4600", NULL }, + { "4700", NULL }, + { "4800", NULL }, + { "4900", NULL }, + { "5000", NULL }, + { NULL, NULL }, + }, + "0" + }, + { + "ppsspp_forced_first_connect", + "Forced First Connect (Faster connect)", + NULL, + NULL, + NULL, + "network", + BOOL_OPTIONS, + "disabled" + }, + { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, +}; + +struct retro_core_options_v2 options_us = { + option_cats_us, + option_defs_us +}; + +/* + ******************************** + * Language Mapping + ******************************** +*/ + +#ifndef HAVE_NO_LANGEXTRA +struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = { + &options_us, /* RETRO_LANGUAGE_ENGLISH */ + NULL, /* RETRO_LANGUAGE_JAPANESE */ + NULL, /* RETRO_LANGUAGE_FRENCH */ + NULL, /* RETRO_LANGUAGE_SPANISH */ + NULL, /* RETRO_LANGUAGE_GERMAN */ + NULL, /* RETRO_LANGUAGE_ITALIAN */ + NULL, /* RETRO_LANGUAGE_DUTCH */ + NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ + NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ + NULL, /* RETRO_LANGUAGE_RUSSIAN */ + NULL, /* RETRO_LANGUAGE_KOREAN */ + NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ + NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ + NULL, /* RETRO_LANGUAGE_ESPERANTO */ + NULL, /* RETRO_LANGUAGE_POLISH */ + NULL, /* RETRO_LANGUAGE_VIETNAMESE */ + NULL, /* RETRO_LANGUAGE_ARABIC */ + NULL, /* RETRO_LANGUAGE_GREEK */ + NULL, /* RETRO_LANGUAGE_TURKISH */ + NULL, /* RETRO_LANGUAGE_SLOVAK */ + NULL, /* RETRO_LANGUAGE_PERSIAN */ + NULL, /* RETRO_LANGUAGE_HEBREW */ + NULL, /* RETRO_LANGUAGE_ASTURIAN */ + NULL, /* RETRO_LANGUAGE_FINNISH */ + NULL, /* RETRO_LANGUAGE_INDONESIAN */ + NULL, /* RETRO_LANGUAGE_SWEDISH */ + NULL, /* RETRO_LANGUAGE_UKRAINIAN */ + NULL, /* RETRO_LANGUAGE_CZECH */ +}; +#endif + +/* + ******************************** + * Functions + ******************************** +*/ + +/* Handles configuration/setting of core options. + * Should be called as early as possible - ideally inside + * retro_set_environment(), and no later than retro_load_game() + * > We place the function body in the header to avoid the + * necessity of adding more .c files (i.e. want this to + * be as painless as possible for core devs) + */ + +static INLINE void libretro_set_core_options(retro_environment_t environ_cb, + bool *categories_supported) +{ + unsigned version = 0; +#ifndef HAVE_NO_LANGEXTRA + unsigned language = 0; +#endif + + if (!environ_cb || !categories_supported) + return; + + *categories_supported = false; + + if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version)) + version = 0; + + if (version >= 2) + { +#ifndef HAVE_NO_LANGEXTRA + struct retro_core_options_v2_intl core_options_intl; + + core_options_intl.us = &options_us; + core_options_intl.local = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && + (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH)) + core_options_intl.local = options_intl[language]; + + *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL, + &core_options_intl); +#else + *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2, + &options_us); +#endif + } + else + { + size_t i, j; + size_t option_index = 0; + size_t num_options = 0; + struct retro_core_option_definition + *option_v1_defs_us = NULL; +#ifndef HAVE_NO_LANGEXTRA + size_t num_options_intl = 0; + struct retro_core_option_v2_definition + *option_defs_intl = NULL; + struct retro_core_option_definition + *option_v1_defs_intl = NULL; + struct retro_core_options_intl + core_options_v1_intl; +#endif + struct retro_variable *variables = NULL; + char **values_buf = NULL; + + /* Determine total number of options */ + while (true) + { + if (option_defs_us[num_options].key) + num_options++; + else + break; + } + + if (version >= 1) + { + /* Allocate US array */ + option_v1_defs_us = (struct retro_core_option_definition *) + calloc(num_options + 1, sizeof(struct retro_core_option_definition)); + + /* Copy parameters from option_defs_us array */ + for (i = 0; i < num_options; i++) + { + struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i]; + struct retro_core_option_value *option_values = option_def_us->values; + struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i]; + struct retro_core_option_value *option_v1_values = option_v1_def_us->values; + + option_v1_def_us->key = option_def_us->key; + option_v1_def_us->desc = option_def_us->desc; + option_v1_def_us->info = option_def_us->info; + option_v1_def_us->default_value = option_def_us->default_value; + + /* Values must be copied individually... */ + while (option_values->value) + { + option_v1_values->value = option_values->value; + option_v1_values->label = option_values->label; + + option_values++; + option_v1_values++; + } + } + +#ifndef HAVE_NO_LANGEXTRA + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && + (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) && + options_intl[language]) + option_defs_intl = options_intl[language]->definitions; + + if (option_defs_intl) + { + /* Determine number of intl options */ + while (true) + { + if (option_defs_intl[num_options_intl].key) + num_options_intl++; + else + break; + } + + /* Allocate intl array */ + option_v1_defs_intl = (struct retro_core_option_definition *) + calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition)); + + /* Copy parameters from option_defs_intl array */ + for (i = 0; i < num_options_intl; i++) + { + struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i]; + struct retro_core_option_value *option_values = option_def_intl->values; + struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i]; + struct retro_core_option_value *option_v1_values = option_v1_def_intl->values; + + option_v1_def_intl->key = option_def_intl->key; + option_v1_def_intl->desc = option_def_intl->desc; + option_v1_def_intl->info = option_def_intl->info; + option_v1_def_intl->default_value = option_def_intl->default_value; + + /* Values must be copied individually... */ + while (option_values->value) + { + option_v1_values->value = option_values->value; + option_v1_values->label = option_values->label; + + option_values++; + option_v1_values++; + } + } + } + + core_options_v1_intl.us = option_v1_defs_us; + core_options_v1_intl.local = option_v1_defs_intl; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl); +#else + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us); +#endif + } + else + { + /* Allocate arrays */ + variables = (struct retro_variable *)calloc(num_options + 1, + sizeof(struct retro_variable)); + values_buf = (char **)calloc(num_options, sizeof(char *)); + + if (!variables || !values_buf) + goto error; + + /* Copy parameters from option_defs_us array */ + for (i = 0; i < num_options; i++) + { + const char *key = option_defs_us[i].key; + const char *desc = option_defs_us[i].desc; + const char *default_value = option_defs_us[i].default_value; + struct retro_core_option_value *values = option_defs_us[i].values; + size_t buf_len = 3; + size_t default_index = 0; + + values_buf[i] = NULL; + + if (desc) + { + size_t num_values = 0; + + /* Determine number of values */ + while (true) + { + if (values[num_values].value) + { + /* Check if this is the default value */ + if (default_value) + if (strcmp(values[num_values].value, default_value) == 0) + default_index = num_values; + + buf_len += strlen(values[num_values].value); + num_values++; + } + else + break; + } + + /* Build values string */ + if (num_values > 0) + { + buf_len += num_values - 1; + buf_len += strlen(desc); + + values_buf[i] = (char *)calloc(buf_len, sizeof(char)); + if (!values_buf[i]) + goto error; + + strcpy(values_buf[i], desc); + strcat(values_buf[i], "; "); + + /* Default value goes first */ + strcat(values_buf[i], values[default_index].value); + + /* Add remaining values */ + for (j = 0; j < num_values; j++) + { + if (j != default_index) + { + strcat(values_buf[i], "|"); + strcat(values_buf[i], values[j].value); + } + } + } + } + + variables[option_index].key = key; + variables[option_index].value = values_buf[i]; + option_index++; + } + + /* Set variables */ + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables); + } + +error: + /* Clean up */ + + if (option_v1_defs_us) + { + free(option_v1_defs_us); + option_v1_defs_us = NULL; + } + +#ifndef HAVE_NO_LANGEXTRA + if (option_v1_defs_intl) + { + free(option_v1_defs_intl); + option_v1_defs_intl = NULL; + } +#endif + + if (values_buf) + { + for (i = 0; i < num_options; i++) + { + if (values_buf[i]) + { + free(values_buf[i]); + values_buf[i] = NULL; + } + } + + free(values_buf); + values_buf = NULL; + } + + if (variables) + { + free(variables); + variables = NULL; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/libretro_core_options_intl.h b/libretro/libretro_core_options_intl.h new file mode 100644 index 0000000000..b2649b6b5e --- /dev/null +++ b/libretro/libretro_core_options_intl.h @@ -0,0 +1,91 @@ +#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__ +#define LIBRETRO_CORE_OPTIONS_INTL_H__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900) +/* https://support.microsoft.com/en-us/kb/980263 */ +#pragma execution_character_set("utf-8") +#pragma warning(disable:4566) +#endif + +#include "libretro.h" + +/* + ******************************** + * VERSION: 2.0 + ******************************** + * + * - 2.0: Add support for core options v2 interface + * - 1.3: Move translations to libretro_core_options_intl.h + * - libretro_core_options_intl.h includes BOM and utf-8 + * fix for MSVC 2010-2013 + * - Added HAVE_NO_LANGEXTRA flag to disable translations + * on platforms/compilers without BOM support + * - 1.2: Use core options v1 interface when + * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1 + * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1) + * - 1.1: Support generation of core options v0 retro_core_option_value + * arrays containing options with a single value + * - 1.0: First commit +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ******************************** + * Core Option Definitions + ******************************** +*/ + +/* RETRO_LANGUAGE_JAPANESE */ + +/* RETRO_LANGUAGE_FRENCH */ + +/* RETRO_LANGUAGE_SPANISH */ + +/* RETRO_LANGUAGE_GERMAN */ + +/* RETRO_LANGUAGE_ITALIAN */ + +/* RETRO_LANGUAGE_DUTCH */ + +/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ + +/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ + +/* RETRO_LANGUAGE_RUSSIAN */ + +/* RETRO_LANGUAGE_KOREAN */ + +/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ + +/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ + +/* RETRO_LANGUAGE_ESPERANTO */ + +/* RETRO_LANGUAGE_POLISH */ + +/* RETRO_LANGUAGE_VIETNAMESE */ + +/* RETRO_LANGUAGE_ARABIC */ + +/* RETRO_LANGUAGE_GREEK */ + +/* RETRO_LANGUAGE_TURKISH */ + +/* RETRO_LANGUAGE_SLOVAK */ + +/* RETRO_LANGUAGE_PERSIAN */ + +/* RETRO_LANGUAGE_HEBREW */ + +/* RETRO_LANGUAGE_ASTURIAN */ + +/* RETRO_LANGUAGE_FINNISH */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/retro_inline.h b/libretro/retro_inline.h new file mode 100644 index 0000000000..b27d6dd6d4 --- /dev/null +++ b/libretro/retro_inline.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_inline.h). + * --------------------------------------------------------------------------------------- + * + * 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. + */ + +#ifndef __LIBRETRO_SDK_INLINE_H +#define __LIBRETRO_SDK_INLINE_H + +#ifndef INLINE + +#if defined(_WIN32) || defined(__INTEL_COMPILER) +#define INLINE __inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L +#define INLINE inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + +#endif +#endif diff --git a/link_readme.py b/link_readme.py index 25cd951b4f..0927769afe 100755 --- a/link_readme.py +++ b/link_readme.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# Requirement: +# python3 -m pip install lxml + import re from time import sleep from urllib.request import urlopen diff --git a/pspautotests b/pspautotests index 2a607edab7..4606502750 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 2a607edab7c3f50d9597c3a2b77082c3be871b55 +Subproject commit 46065027500cd781ce7c15c051c8b0c4751ad1fa diff --git a/source_assets/image/arrow_down.png b/source_assets/image/arrow_down.png new file mode 100644 index 0000000000..d03afcc8d2 Binary files /dev/null and b/source_assets/image/arrow_down.png differ diff --git a/source_assets/image/arrow_left.png b/source_assets/image/arrow_left.png new file mode 100644 index 0000000000..37454034bd Binary files /dev/null and b/source_assets/image/arrow_left.png differ diff --git a/source_assets/image/arrow_right.png b/source_assets/image/arrow_right.png new file mode 100644 index 0000000000..5181723f98 Binary files /dev/null and b/source_assets/image/arrow_right.png differ diff --git a/source_assets/image/arrow_up.png b/source_assets/image/arrow_up.png new file mode 100644 index 0000000000..1e9fb9714d Binary files /dev/null and b/source_assets/image/arrow_up.png differ diff --git a/source_assets/image/buttons.svg b/source_assets/image/buttons.svg index edcca85473..68203e5e4c 100644 --- a/source_assets/image/buttons.svg +++ b/source_assets/image/buttons.svg @@ -1795,7 +1795,7 @@ inkscape:label="Drop Shadow"> + + + + + + + @@ -2145,8 +2180,8 @@ id="rect5044" width="399.68362" height="362.96939" - x="1.3355882" - y="-8.7092419" /> + x="-2.726912" + y="-3.7985277" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source_assets/image/plus.png b/source_assets/image/plus.png new file mode 100644 index 0000000000..f65fb9c48c Binary files /dev/null and b/source_assets/image/plus.png differ diff --git a/source_assets/image/rotate_left.png b/source_assets/image/rotate_left.png new file mode 100644 index 0000000000..b7c9f40db9 Binary files /dev/null and b/source_assets/image/rotate_left.png differ diff --git a/source_assets/image/rotate_right.png b/source_assets/image/rotate_right.png new file mode 100644 index 0000000000..ddd4933fd6 Binary files /dev/null and b/source_assets/image/rotate_right.png differ diff --git a/source_assets/image/sliders.png b/source_assets/image/sliders.png new file mode 100644 index 0000000000..2ec872f0ff Binary files /dev/null and b/source_assets/image/sliders.png differ diff --git a/source_assets/image/three_dots.png b/source_assets/image/three_dots.png new file mode 100644 index 0000000000..9001c4fc17 Binary files /dev/null and b/source_assets/image/three_dots.png differ diff --git a/source_assets/image/trashcan.png b/source_assets/image/trashcan.png new file mode 100644 index 0000000000..d761236539 Binary files /dev/null and b/source_assets/image/trashcan.png differ diff --git a/test.py b/test.py index 2ae8d9237d..7b55c8a692 100755 --- a/test.py +++ b/test.py @@ -69,6 +69,7 @@ tests_good = [ "cpu/cpu_alu/cpu_branch", "cpu/cpu_alu/cpu_branch2", "cpu/vfpu/colors", + "cpu/vfpu/convert", "cpu/vfpu/gum", "cpu/vfpu/matrix", "cpu/vfpu/vavg", @@ -138,6 +139,10 @@ tests_good = [ "font/optimum", "font/resolution", "font/shadowimagerect", + "gpu/bounding/count", + "gpu/bounding/planes", + "gpu/bounding/vertexaddr", + "gpu/bounding/viewport", "gpu/callbacks/ge_callbacks", "gpu/clipping/homogeneous", "gpu/clut/address", @@ -163,6 +168,7 @@ tests_good = [ "gpu/primitives/indices", "gpu/primitives/invalidprim", "gpu/primitives/points", + "gpu/primitives/rectangles", "gpu/primitives/trianglefan", "gpu/primitives/trianglestrip", "gpu/primitives/triangles", @@ -185,7 +191,12 @@ tests_good = [ "gpu/texfunc/replace", "gpu/textures/mipmap", "gpu/textures/rotate", + "gpu/transfer/invalid", + "gpu/transfer/mirrors", + "gpu/transfer/overlap", "gpu/vertices/colors", + "gpu/vertices/morph", + "gpu/vertices/texcoords", "hash/hash", "hle/check_not_used_uids", "intr/intr", @@ -193,6 +204,7 @@ tests_good = [ "intr/suspended", "intr/vblank/vblank", "io/cwd/cwd", + "io/open/badparent", "jpeg/create", "jpeg/delete", "jpeg/finish", @@ -366,7 +378,6 @@ tests_good = [ tests_next = [ # These are the next tests up for fixing. These run by default. "cpu/fpu/fcr", - "cpu/vfpu/convert", "cpu/vfpu/prefixes", "cpu/vfpu/vector", "cpu/vfpu/vregs", @@ -412,7 +423,6 @@ tests_next = [ "gpu/primitives/immediate", "gpu/primitives/lines", "gpu/primitives/linestrip", - "gpu/primitives/rectangles", "gpu/primitives/spline", "gpu/reflection/reflection", "gpu/rendertarget/rendertarget", @@ -426,7 +436,6 @@ tests_next = [ "gpu/texmtx/uvs", "gpu/textures/size", "gpu/triangle/triangle", - "gpu/vertices/texcoords", "intr/registersub", "intr/releasesub", "intr/waits", diff --git a/ui_atlasscript.txt b/ui_atlasscript.txt index cbb3a2b22a..eead48f3f2 100644 --- a/ui_atlasscript.txt +++ b/ui_atlasscript.txt @@ -60,3 +60,13 @@ image I_SQUARE_SHAPE source_assets/image/square_shape.png copy image I_SQUARE_SHAPE_LINE source_assets/image/square_shape_line.png copy image I_FOLDER_OPEN source_assets/image/folder_open_line.png copy image I_WARNING source_assets/image/warning.png copy +image I_TRASHCAN source_assets/image/trashcan.png copy +image I_PLUS source_assets/image/plus.png copy +image I_ROTATE_LEFT source_assets/image/rotate_left.png copy +image I_ROTATE_RIGHT source_assets/image/rotate_right.png copy +image I_ARROW_LEFT source_assets/image/arrow_left.png copy +image I_ARROW_RIGHT source_assets/image/arrow_right.png copy +image I_ARROW_UP source_assets/image/arrow_up.png copy +image I_ARROW_DOWN source_assets/image/arrow_down.png copy +image I_SLIDERS source_assets/image/sliders.png copy +image I_THREE_DOTS source_assets/image/three_dots.png copy diff --git a/unittest/TestArm64Emitter.cpp b/unittest/TestArm64Emitter.cpp index af0f37ca45..a795cfbb2f 100644 --- a/unittest/TestArm64Emitter.cpp +++ b/unittest/TestArm64Emitter.cpp @@ -8,7 +8,7 @@ #include "UnitTest.h" -static bool CheckLast(Arm64Gen::ARM64XEmitter &emit, const char *comp) { +static bool CheckLast(const Arm64Gen::ARM64XEmitter &emit, const char *comp) { u32 instr; memcpy(&instr, emit.GetCodePointer() - 4, 4); char disasm[512]; diff --git a/unittest/TestArmEmitter.cpp b/unittest/TestArmEmitter.cpp index 94acdbdb1f..848655058a 100644 --- a/unittest/TestArmEmitter.cpp +++ b/unittest/TestArmEmitter.cpp @@ -2,6 +2,7 @@ #include "Core/MIPS/ARM/ArmRegCacheFPU.h" #include "Core/MIPS/ARM/ArmJit.h" #include "Core/MIPS/JitCommon/JitState.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSVFPUUtils.h" #include "ext/disarm.h" @@ -9,7 +10,7 @@ #include "UnitTest.h" -static bool CheckLast(ArmGen::ARMXEmitter &emit, const char *comp) { +static bool CheckLast(const ArmGen::ARMXEmitter &emit, const char *comp) { u32 instr; memcpy(&instr, emit.GetCodePointer() - 4, 4); char disasm[512]; diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index d5f2f9cc55..89e0eaafec 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -28,32 +28,36 @@ static constexpr size_t CODE_BUFFER_SIZE = 32768; bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { + buffer[0] = '\0'; + + FragmentShaderFlags flags; + uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, nullptr, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString); } default: return false; @@ -61,33 +65,37 @@ bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs } bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { + buffer[0] = '\0'; + + VertexShaderFlags flags; + uint32_t attrMask; uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString); } default: return false; @@ -95,6 +103,8 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs } bool GenerateGShader(GShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { + buffer[0] = '\0'; + errorString->clear(); switch (lang) { @@ -243,7 +253,7 @@ bool TestReinterpretShaders() { for (int j = 0; j < 3; j++) { if (i == j) continue; // useless shader! - ShaderWriter writer(buffer, desc, ShaderStage::Fragment, nullptr, 0); + ShaderWriter writer(buffer, desc, ShaderStage::Fragment); GenerateReinterpretFragmentShader(writer, fmts[i], fmts[j]); if (strlen(buffer) >= 8192) { printf("Reinterpret fragment shader %d exceeded buffer:\n\n%s\n", (int)j, LineNumberString(buffer).c_str()); @@ -285,17 +295,21 @@ bool TestStencilShaders() { ShaderLanguageDesc desc(languages[k]); std::string errorMessage; - // Generate all despite failures - it's only 6. - GenerateStencilFs(buffer, desc, bugs); - if (strlen(buffer) >= 8192) { - printf("Stencil fragment shader exceeded buffer:\n\n%s\n", LineNumberString(buffer).c_str()); - failed = true; - } - if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { - printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); - failed = true; - } else { - printf("===\n%s\n===\n", buffer); + // Generate all despite failures - it's only a few. + // Only use export on Vulkan, because GLSL_3xx is ES which doesn't support stencil export. + bool allowUseExport = languages[k] == ShaderLanguage::GLSL_VULKAN; + for (int useExport = 0; useExport <= (allowUseExport ? 1 : 0); ++useExport) { + GenerateStencilFs(buffer, desc, bugs, useExport == 1); + if (strlen(buffer) >= 8192) { + printf("Stencil fragment shader (useExport=%d) exceeded buffer:\n\n%s\n", useExport, LineNumberString(buffer).c_str()); + failed = true; + } + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { + printf("Error compiling stencil shader (useExport=%d):\n\n%s\n\n%s\n", useExport, LineNumberString(buffer).c_str(), errorMessage.c_str()); + failed = true; + } else { + printf("===\n%s\n===\n", buffer); + } } GenerateStencilVs(buffer, desc); diff --git a/unittest/TestSoftwareGPUJit.cpp b/unittest/TestSoftwareGPUJit.cpp index 54b8ceda52..5d7c6946d4 100644 --- a/unittest/TestSoftwareGPUJit.cpp +++ b/unittest/TestSoftwareGPUJit.cpp @@ -18,6 +18,7 @@ #include "Common/Data/Random/Rng.h" #include "Common/StringUtils.h" #include "Core/Config.h" +#include "GPU/Software/BinManager.h" #include "GPU/Software/DrawPixel.h" #include "GPU/Software/Sampler.h" #include "GPU/Software/SoftGpu.h" @@ -25,21 +26,22 @@ static bool TestSamplerJit() { using namespace Sampler; SamplerJitCache *cache = new SamplerJitCache(); + BinManager binner; auto GetLinear = [&](SamplerID &id) { id.linear = true; id.fetch = false; - return cache->GetLinear(id); + return cache->GetLinear(id, &binner); }; auto GetNearest = [&](SamplerID &id) { id.linear = false; id.fetch = false; - return cache->GetNearest(id); + return cache->GetNearest(id, &binner); }; auto GetFetch = [&](SamplerID &id) { id.linear = false; id.fetch = true; - return cache->GetFetch(id); + return cache->GetFetch(id, &binner); }; GMRng rng; @@ -89,8 +91,8 @@ static bool TestSamplerJit() { // Try running each to make sure they don't trivially crash. const auto primArg = Rasterizer::ToVec4IntArg(Math3D::Vec4(127, 127, 127, 127)); - linearFunc(0.0f, 0.0f, 0, 0, primArg, tptr, bufw, 1, 7, id); - nearestFunc(0.0f, 0.0f, 0, 0, primArg, tptr, bufw, 1, 7, id); + linearFunc(0.0f, 0.0f, primArg, tptr, bufw, 1, 7, id); + nearestFunc(0.0f, 0.0f, primArg, tptr, bufw, 1, 7, id); fetchFunc(0, 0, tptr[0], bufw[0], 1, id); } @@ -111,6 +113,7 @@ static bool TestSamplerJit() { static bool TestPixelJit() { using namespace Rasterizer; PixelJitCache *cache = new PixelJitCache(); + BinManager binner; GMRng rng; int successes = 0; @@ -134,7 +137,7 @@ static bool TestPixelJit() { continue; i++; - SingleFunc func = cache->GetSingle(id); + SingleFunc func = cache->GetSingle(id, &binner); SingleFunc genericFunc = cache->GenericSingle(id); if (func != genericFunc) { successes++; diff --git a/unittest/TestThreadManager.cpp b/unittest/TestThreadManager.cpp index 1457c587ed..ece88ca494 100644 --- a/unittest/TestThreadManager.cpp +++ b/unittest/TestThreadManager.cpp @@ -74,8 +74,8 @@ class IncrementTask : public Task { public: IncrementTask(TaskType type, LimitedWaitable *waitable) : type_(type), waitable_(waitable) {} ~IncrementTask() {} - virtual TaskType Type() const { return type_; } - virtual void Run() { + TaskType Type() const override { return type_; } + void Run() override { g_atomicCounter++; waitable_->Notify(); } diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp index 573247ba38..12dad2f5aa 100644 --- a/unittest/TestVertexJit.cpp +++ b/unittest/TestVertexJit.cpp @@ -545,8 +545,10 @@ static bool TestVertexColor565() { static bool TestVertex8Skin() { VertexDecoderTestHarness dec; + VertexDecoderOptions opts{}; + opts.applySkinInDecode = true; + dec.SetOptions(opts); - g_Config.bSoftwareSkinning = true; for (int i = 0; i < 8 * 12; ++i) { gstate.boneMatrix[i] = 0.0f; } @@ -575,8 +577,10 @@ static bool TestVertex8Skin() { static bool TestVertex16Skin() { VertexDecoderTestHarness dec; + VertexDecoderOptions opts{}; + opts.applySkinInDecode = true; + dec.SetOptions(opts); - g_Config.bSoftwareSkinning = true; for (int i = 0; i < 8 * 12; ++i) { gstate.boneMatrix[i] = 0.0f; } @@ -605,8 +609,10 @@ static bool TestVertex16Skin() { static bool TestVertexFloatSkin() { VertexDecoderTestHarness dec; + VertexDecoderOptions opts{}; + opts.applySkinInDecode = true; + dec.SetOptions(opts); - g_Config.bSoftwareSkinning = true; for (int i = 0; i < 8 * 12; ++i) { gstate.boneMatrix[i] = 0.0f; } diff --git a/unittest/TestX64Emitter.cpp b/unittest/TestX64Emitter.cpp index c92b415d12..14f1a003c2 100644 --- a/unittest/TestX64Emitter.cpp +++ b/unittest/TestX64Emitter.cpp @@ -14,13 +14,13 @@ static const u8 *prevStart = NULL; -bool CheckLast(Gen::XEmitter &emit, const char *comp) { +static bool CheckLast(const Gen::XEmitter &emit, const char *comp) { auto vec = DisassembleX86(prevStart, (int)(emit.GetCodePointer() - prevStart)); EXPECT_EQ_STR(vec[0], std::string(comp)); return true; } -void PrintLast(Gen::XEmitter &emit) { +static void PrintLast(const Gen::XEmitter &emit) { for (const u8 *p = prevStart; p < emit.GetCodePointer(); p++) { printf("%02x ", *p); } diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index bb3d9d112b..1284584607 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -41,6 +41,7 @@ #endif #include "Common/Data/Collections/TinySet.h" +#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Data/Text/Parsers.h" #include "Common/Data/Text/WrapText.h" #include "Common/Data/Encoding/Utf8.h" @@ -782,6 +783,15 @@ static bool TestWrapText() { return true; } +static bool TestSmallDataConvert() { + float f[4] = { 1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.f }; + uint32_t result = Float4ToUint8x4_NoClamp(f); + EXPECT_EQ_HEX(result, 0x04030201); + result = Float4ToUint8x4(f); + EXPECT_EQ_HEX(result, 0x04030201); + return true; +} + typedef bool (*TestFunc)(); struct TestItem { const char *name; @@ -832,6 +842,7 @@ TestItem availableTests[] = { TEST_ITEM(ThreadManager), TEST_ITEM(WrapText), TEST_ITEM(TinySet), + TEST_ITEM(SmallDataConvert), }; int main(int argc, const char *argv[]) {