mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-21 02:09:05 +02:00
Merge branch 'master' into fix-core-gpu-always-true
This commit is contained in:
833 files changed
+41498
-19840
No files matched your search
@@ -29,6 +29,10 @@ charset = utf-8-bom
|
||||
[Windows/{aboutbox.rc,version.rc}]
|
||||
charset = utf-8
|
||||
|
||||
[ext/at3_standalone/**.{cpp,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[libretro/**.{cpp,h}]
|
||||
indent_style = space
|
||||
indent_size = 3
|
||||
|
||||
@@ -127,7 +127,7 @@ body:
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed."
|
||||
- label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed."
|
||||
required: true
|
||||
- label: "[Search for other reports](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same issue."
|
||||
required: true
|
||||
|
||||
@@ -84,7 +84,7 @@ body:
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed."
|
||||
- label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed."
|
||||
required: true
|
||||
- label: "Make sure to run `git submodule update --init --recursive` before building."
|
||||
required: true
|
||||
|
||||
@@ -68,7 +68,7 @@ body:
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: "Check the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already implemented."
|
||||
- label: "Check the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already implemented."
|
||||
required: true
|
||||
- label: "[Search for other requests](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same feature."
|
||||
required: true
|
||||
@@ -141,7 +141,7 @@ body:
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed."
|
||||
- label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed."
|
||||
required: true
|
||||
- label: "[Search for other reports](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same issue."
|
||||
required: true
|
||||
|
||||
@@ -125,7 +125,7 @@ body:
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed."
|
||||
- label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed."
|
||||
required: true
|
||||
- label: "[Search for other reports](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same issue."
|
||||
required: true
|
||||
|
||||
+50
-13
@@ -34,12 +34,12 @@ jobs:
|
||||
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Build Windows
|
||||
working-directory: ${{ env.GITHUB_WORKSPACE }}
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
run: cp Windows/Release/*.exe ppsspp/
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows ${{ matrix.platform }} build
|
||||
path: ppsspp/
|
||||
@@ -71,12 +71,12 @@ jobs:
|
||||
build-uwp:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Build UWP
|
||||
working-directory: ${{ env.GITHUB_WORKSPACE }}
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
needs: build-windows
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
run: git submodule update --init pspautotests assets/lang
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: Windows x64 build
|
||||
path: ppsspp/
|
||||
@@ -192,7 +192,7 @@ jobs:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -203,7 +203,7 @@ jobs:
|
||||
git fetch --deepen=15000 --no-recurse-submodules --tags || exit 0
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
uses: jurplel/install-qt-action@v4
|
||||
if: matrix.extra == 'qt'
|
||||
with:
|
||||
cache: true
|
||||
@@ -285,7 +285,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: matrix.extra == 'test'
|
||||
with:
|
||||
name: ${{ matrix.os }} build
|
||||
@@ -298,7 +298,7 @@ jobs:
|
||||
mv PPSSPPSDL.zip PPSSPPSDL-macOS-${GITHUB_REF##*/}.zip || exit 1
|
||||
|
||||
- name: Upload macOS release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/') && runner.os == 'macOS' && matrix.extra == 'test'
|
||||
with:
|
||||
files: ppsspp/*.zip
|
||||
@@ -319,7 +319,7 @@ jobs:
|
||||
needs: build
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
|
||||
@@ -341,7 +341,7 @@ jobs:
|
||||
git submodule update --init SDL/macOS
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.os }} build
|
||||
path: ppsspp/
|
||||
@@ -362,3 +362,40 @@ jobs:
|
||||
- name: Execute headless tests
|
||||
working-directory: ${{ env.GITHUB_WORKSPACE }}
|
||||
run: python test.py -g --graphics=software
|
||||
|
||||
build_test_headless_alpine:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alpine:latest
|
||||
options: --shm-size=8g
|
||||
steps:
|
||||
- name: Install Linux dependencies (Alpine)
|
||||
run: |
|
||||
apk add build-base wget git bash cmake python3 glu-dev sdl2-dev
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Fix git detected dubious ownership in repository
|
||||
run: |
|
||||
chown -R $(id -u):$(id -g) $PWD
|
||||
|
||||
- name: Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: Compile ffmpeg
|
||||
run: |
|
||||
cd ffmpeg && ./linux_x86-64.sh
|
||||
|
||||
- name: Build for testing
|
||||
run: |
|
||||
./b.sh --headless --unittest
|
||||
|
||||
- name: Execute unit tests
|
||||
run: |
|
||||
./build/PPSSPPUnitTest ALL
|
||||
|
||||
- name: Execute headless tests
|
||||
run: |
|
||||
python test.py -g --graphics=software
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
registry: ghcr.io
|
||||
|
||||
- uses: docker/build-push-action@v3
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_TAG }}
|
||||
@@ -11,6 +11,9 @@ on:
|
||||
options:
|
||||
- NormalOptimized
|
||||
- NormalDebug
|
||||
- VROptimized
|
||||
- VRDebug
|
||||
- LegacyOptimized
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
@@ -66,8 +66,13 @@ jobs:
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
USE_CCACHE: 1
|
||||
run: |
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
export CCACHE_SLOPPINESS=pch_defines,clang_index_store,ivfsoverlay,include_file_ctime,include_file_mtime,modules,system_headers,time_macros
|
||||
export CCACHE_FILECLONE=true
|
||||
export CCACHE_DEPEND=true
|
||||
export CCACHE_COMPILERCHECK=content
|
||||
./b.sh --ios --${{ github.event.inputs.buildVariant }}
|
||||
|
||||
- name: Package build
|
||||
|
||||
@@ -136,6 +136,8 @@ build
|
||||
libretro/obj/local
|
||||
|
||||
ppsspp_retroachievements.dat
|
||||
RACache
|
||||
RAPrefs_PPSSPP.cfg
|
||||
|
||||
# For CLion
|
||||
cmake-build-*/
|
||||
@@ -103,6 +103,8 @@ libretro-build-linux-i686:
|
||||
libretro-build-osx-x64:
|
||||
tags:
|
||||
- macosx-packaging
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -DUSE_SYSTEM_LIBPNG=OFF
|
||||
extends:
|
||||
- .libretro-osx-cmake-x86_64
|
||||
- .core-defs
|
||||
|
||||
+4
-1
@@ -30,7 +30,7 @@
|
||||
url = https://github.com/hrydgard/ppsspp-freetype.git
|
||||
[submodule "ext/miniupnp"]
|
||||
path = ext/miniupnp
|
||||
url = https://github.com/hrydgard/miniupnp.git
|
||||
url = https://github.com/miniupnp/miniupnp.git
|
||||
[submodule "zstd"]
|
||||
path = ext/zstd
|
||||
url = https://github.com/facebook/zstd.git
|
||||
@@ -59,3 +59,6 @@
|
||||
[submodule "ext/OpenXR-SDK"]
|
||||
path = ext/OpenXR-SDK
|
||||
url = https://github.com/KhronosGroup/OpenXR-SDK.git
|
||||
[submodule "ios/MoltenVK"]
|
||||
path = ios/MoltenVK
|
||||
url = https://github.com/hrydgard/ppsspp-moltenvk.git
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "build/PPSSPPSDL",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "C/C++: build",
|
||||
"command": "./b.sh",
|
||||
"args": [
|
||||
"--debug",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "compiler: /usr/bin/g++"
|
||||
},
|
||||
]
|
||||
}
|
||||
+210
-53
@@ -1,5 +1,5 @@
|
||||
# vim:noexpandtab:
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(PPSSPP)
|
||||
enable_testing()
|
||||
|
||||
@@ -131,7 +131,20 @@ if(GOLD)
|
||||
add_definitions(-DGOLD)
|
||||
message("Gold Build")
|
||||
else()
|
||||
message("Normal Build")
|
||||
message("Non-gold Build")
|
||||
endif()
|
||||
|
||||
if(IOS_APP_STORE)
|
||||
add_definitions(-DPPSSPP_PLATFORM_IOS_APP_STORE)
|
||||
add_definitions(-DGLES_SILENCE_DEPRECATION)
|
||||
# Set a global default to not generate schemes for each target.
|
||||
# Makes using XCode sligthly more sane.
|
||||
set(CMAKE_XCODE_GENERATE_SCHEME NO)
|
||||
set(CMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION FALSE)
|
||||
set(CMAKE_XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE DISABLED)
|
||||
message("iOS App Store build")
|
||||
elseif(IOS)
|
||||
message("iOS sideload build")
|
||||
endif()
|
||||
|
||||
# User-editable options (go into CMakeCache.txt)
|
||||
@@ -173,6 +186,7 @@ option(USE_SYSTEM_MINIUPNPC "Dynamically link against system miniUPnPc" ${USE_SY
|
||||
option(USE_ASAN "Use address sanitizer" OFF)
|
||||
option(USE_UBSAN "Use undefined behaviour sanitizer" OFF)
|
||||
option(USE_CCACHE "Use ccache if detected" ON)
|
||||
option(USE_NO_MMAP "Disable mmap usage" OFF)
|
||||
|
||||
if(USE_CCACHE)
|
||||
include(ccache)
|
||||
@@ -234,6 +248,12 @@ if(HTTPS_NOT_AVAILABLE)
|
||||
add_definitions(-DHTTPS_NOT_AVAILABLE)
|
||||
endif()
|
||||
|
||||
# Disable the usage of MMAP for the memory system.
|
||||
# It is not tested on all platforms and can cause issues.
|
||||
if(USE_NO_MMAP)
|
||||
add_definitions(-DNO_MMAP -DMASKED_PSP_MEMORY)
|
||||
endif()
|
||||
|
||||
# Work around for some misfeature of the current glslang build system
|
||||
include_directories(ext/glslang)
|
||||
|
||||
@@ -312,6 +332,8 @@ endif()
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
else()
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
message("CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
@@ -364,9 +386,17 @@ if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
|
||||
endif()
|
||||
if(CLANG)
|
||||
add_definitions(-Wno-nullability-completeness)
|
||||
add_definitions(-Wno-tautological-pointer-compare)
|
||||
add_definitions(-Wno-deprecated-register)
|
||||
add_definitions(
|
||||
-Wno-nullability-completeness
|
||||
-Wno-tautological-pointer-compare
|
||||
-Wno-deprecated-register
|
||||
-Wno-sign-conversion
|
||||
-Wno-shorten-64-to-32
|
||||
)
|
||||
if(MACOSX OR IOS)
|
||||
# Hack around a bad check for __GNUC__ in basis_universal that makes it use old stuff on iOS
|
||||
add_definitions(-Wno-deprecated-builtins)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_ASAN)
|
||||
@@ -422,7 +452,7 @@ if(NOT MSVC)
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
|
||||
elseif(APPLE AND NOT CMAKE_CROSSCOMPILING)
|
||||
if(LIBRETRO AND ARM64)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
|
||||
@@ -840,8 +870,6 @@ add_library(Common STATIC
|
||||
Common/Common.h
|
||||
Common/CommonFuncs.h
|
||||
Common/CommonTypes.h
|
||||
Common/ConsoleListener.cpp
|
||||
Common/ConsoleListener.h
|
||||
Common/DbgNew.h
|
||||
Common/FakeEmitter.h
|
||||
Common/FakeCPUDetect.cpp
|
||||
@@ -849,8 +877,12 @@ add_library(Common STATIC
|
||||
Common/ExceptionHandlerSetup.h
|
||||
Common/Log.h
|
||||
Common/Log.cpp
|
||||
Common/LogManager.cpp
|
||||
Common/LogManager.h
|
||||
Common/Log/ConsoleListener.cpp
|
||||
Common/Log/ConsoleListener.h
|
||||
Common/Log/StdioListener.cpp
|
||||
Common/Log/StdioListener.h
|
||||
Common/Log/LogManager.cpp
|
||||
Common/Log/LogManager.h
|
||||
Common/LogReporting.cpp
|
||||
Common/LogReporting.h
|
||||
Common/MemArenaAndroid.cpp
|
||||
@@ -1250,6 +1282,12 @@ if(OPENXR AND NOT ARMV7_DEVICE)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} openxr_loader)
|
||||
endif()
|
||||
|
||||
if(IOS OR MACOSX)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
Common/Render/Text/draw_text_cocoa.mm
|
||||
Common/Render/Text/draw_text_cocoa.h)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(NativeAppSource ${NativeAppSource}
|
||||
android/jni/app-android.cpp
|
||||
@@ -1271,8 +1309,13 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
ios/AppDelegate.h
|
||||
ios/DisplayManager.h
|
||||
ios/DisplayManager.mm
|
||||
ios/Controls.h
|
||||
ios/Controls.mm
|
||||
ios/ViewControllerCommon.h
|
||||
ios/ViewController.mm
|
||||
ios/ViewController.h
|
||||
ios/ViewControllerMetal.mm
|
||||
ios/ViewControllerMetal.h
|
||||
ios/iOSCoreAudio.mm
|
||||
ios/iOSCoreAudio.h
|
||||
ios/CameraHelper.mm
|
||||
@@ -1291,7 +1334,7 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
Common/Battery/AppleBatteryClient.m
|
||||
)
|
||||
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreVideo -framework CoreMedia -framework CoreServices" )
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework CoreMotion -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreText -framework CoreVideo -framework CoreMedia -framework CoreServices -framework Metal -framework IOSurface" )
|
||||
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
|
||||
endif()
|
||||
@@ -1300,16 +1343,23 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} iconv)
|
||||
endif()
|
||||
|
||||
# TODO: Enable arc globally?
|
||||
set_source_files_properties(ios/AppDelegate.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/ViewController.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/ViewControllerMetal.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/iOSCoreAudio.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/PPSSPPUIApplication.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/iCade/iCadeReaderView.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/main.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/CameraHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/AudioEngine.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/LocationHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/DisplayManager.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(ios/Controls.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
|
||||
set(TargetBin PPSSPP)
|
||||
elseif(IOS AND LIBRETRO)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework GLKit")
|
||||
@@ -1333,6 +1383,7 @@ elseif(USING_QT_UI)
|
||||
Common/Battery/AppleBatteryClient.m)
|
||||
set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY})
|
||||
endif()
|
||||
include_directories(Qt)
|
||||
@@ -1410,11 +1461,16 @@ else()
|
||||
UI/PSPNSApplicationDelegate.mm
|
||||
UI/PSPNSApplicationDelegate.h)
|
||||
|
||||
# TODO
|
||||
# set_source_files_properties(SDL/SDLMain.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
|
||||
set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(UI/PSPNSApplicationDelegate.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(SDL/CocoaMetalLayer.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(SDL/CocoaBarItems.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(SDL/PPSSPPAboutViewController.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY})
|
||||
|
||||
if(USE_SYSTEM_LIBSDL2)
|
||||
@@ -1507,6 +1563,8 @@ list(APPEND NativeAppSource
|
||||
UI/CwCheatScreen.cpp
|
||||
UI/InstallZipScreen.h
|
||||
UI/InstallZipScreen.cpp
|
||||
UI/JitCompareScreen.h
|
||||
UI/JitCompareScreen.cpp
|
||||
UI/MemStickScreen.h
|
||||
UI/MemStickScreen.cpp
|
||||
UI/ProfilerDraw.h
|
||||
@@ -1858,6 +1916,8 @@ set(GPU_SOURCES
|
||||
GPU/Common/SoftwareTransformCommon.h
|
||||
GPU/Common/VertexDecoderCommon.cpp
|
||||
GPU/Common/VertexDecoderCommon.h
|
||||
GPU/Common/VertexDecoderHandwritten.cpp
|
||||
GPU/Common/VertexDecoderHandwritten.h
|
||||
GPU/Common/TransformCommon.cpp
|
||||
GPU/Common/TransformCommon.h
|
||||
GPU/Common/IndexGenerator.cpp
|
||||
@@ -2079,6 +2139,10 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/HLE/__sceAudio.h
|
||||
Core/HLE/sceAdler.cpp
|
||||
Core/HLE/sceAdler.h
|
||||
Core/HLE/AtracCtx.cpp
|
||||
Core/HLE/AtracCtx.h
|
||||
Core/HLE/AtracCtx2.cpp
|
||||
Core/HLE/AtracCtx2.h
|
||||
Core/HLE/sceAtrac.cpp
|
||||
Core/HLE/sceAtrac.h
|
||||
Core/HLE/sceAudio.cpp
|
||||
@@ -2215,6 +2279,9 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/HLE/scePauth.h
|
||||
Core/HW/SimpleAudioDec.cpp
|
||||
Core/HW/SimpleAudioDec.h
|
||||
Core/HW/Atrac3Standalone.cpp
|
||||
Core/HW/Atrac3Standalone.h
|
||||
Core/HW/SimpleAudioDec.h
|
||||
Core/HW/AsyncIOManager.cpp
|
||||
Core/HW/AsyncIOManager.h
|
||||
Core/HW/BufferQueue.cpp
|
||||
@@ -2275,6 +2342,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/MIPS/MIPSVFPUFallbacks.h
|
||||
Core/MIPS/MIPSAsm.cpp
|
||||
Core/MIPS/MIPSAsm.h
|
||||
Core/MIPS/MIPSTracer.cpp
|
||||
Core/MIPS/MIPSTracer.h
|
||||
Core/MemFault.cpp
|
||||
Core/MemFault.h
|
||||
Core/MemMap.cpp
|
||||
@@ -2354,16 +2423,14 @@ if(USE_SYSTEM_ZSTD)
|
||||
target_include_directories(${CoreLibName} PRIVATE ${ZSTD_INCLUDE_DIR})
|
||||
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)
|
||||
add_subdirectory(ext/zstd-build)
|
||||
set(CoreExtraLibs ${CoreExtraLibs} libzstd_static)
|
||||
include_directories(ext/zstd/lib)
|
||||
endif()
|
||||
|
||||
include_directories(ext/libchdr/include)
|
||||
|
||||
target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos ${GlslangLibs}
|
||||
target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 at3_standalone ${GlslangLibs}
|
||||
${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||
|
||||
if(NOT HTTPS_NOT_AVAILABLE)
|
||||
@@ -2406,8 +2473,8 @@ if(USE_MINIUPNPC)
|
||||
target_link_libraries(${CoreLibName} ${MINIUPNP_LIBRARY})
|
||||
add_definitions(-DWITH_UPNP -DUSE_SYSTEM_MINIUPNPC)
|
||||
else()
|
||||
set (MINIUPNPC_VERSION 2.1) # used by miniupnpcstrings.h.cmake
|
||||
set (MINIUPNPC_API_VERSION 17)
|
||||
set (MINIUPNPC_VERSION 2.2) # used by miniupnpcstrings.h.cmake
|
||||
set (MINIUPNPC_API_VERSION 18)
|
||||
option(UPNPC_BUILD_STATIC "Build static library" TRUE)
|
||||
option(NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE)
|
||||
mark_as_advanced(NO_GETADDRINFO)
|
||||
@@ -2431,25 +2498,28 @@ if(USE_MINIUPNPC)
|
||||
add_definitions(-DWITH_UPNP -DMINIUPNP_STATICLIB)
|
||||
set(MINIUPNP_DIR "ext/miniupnp/miniupnpc")
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(ext/miniupnp/miniupnpc/src)
|
||||
include_directories(ext/miniupnp/miniupnpc/include)
|
||||
configure_file(${MINIUPNP_DIR}/miniupnpcstrings.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h) # by default miniupnp repo doesn't contains miniupnpcstrings.h and need to be generated
|
||||
set(MINIUPNPC_SOURCES
|
||||
# the needed bits of miniupnpc (no python module, no tests, no cli)
|
||||
${MINIUPNP_DIR}/addr_is_reserved.c
|
||||
${MINIUPNP_DIR}/connecthostport.c
|
||||
${MINIUPNP_DIR}/igd_desc_parse.c
|
||||
${MINIUPNP_DIR}/minisoap.c
|
||||
${MINIUPNP_DIR}/minissdpc.c
|
||||
${MINIUPNP_DIR}/miniupnpc.c
|
||||
${MINIUPNP_DIR}/miniwget.c
|
||||
${MINIUPNP_DIR}/minixml.c
|
||||
${MINIUPNP_DIR}/minixmlvalid.c
|
||||
${MINIUPNP_DIR}/portlistingparse.c
|
||||
${MINIUPNP_DIR}/receivedata.c
|
||||
${MINIUPNP_DIR}/src/addr_is_reserved.c
|
||||
${MINIUPNP_DIR}/src/connecthostport.c
|
||||
${MINIUPNP_DIR}/src/igd_desc_parse.c
|
||||
${MINIUPNP_DIR}/src/minisoap.c
|
||||
${MINIUPNP_DIR}/src/minissdpc.c
|
||||
${MINIUPNP_DIR}/src/miniupnpc.c
|
||||
#${MINIUPNP_DIR}/miniupnpcmodule.c
|
||||
${MINIUPNP_DIR}/src/miniwget.c
|
||||
${MINIUPNP_DIR}/src/minixml.c
|
||||
${MINIUPNP_DIR}/src/minixmlvalid.c
|
||||
${MINIUPNP_DIR}/src/portlistingparse.c
|
||||
${MINIUPNP_DIR}/src/receivedata.c
|
||||
#${MINIUPNP_DIR}/upnpc.c # causing an error due to already existing _main()
|
||||
${MINIUPNP_DIR}/upnpcommands.c
|
||||
${MINIUPNP_DIR}/upnpdev.c
|
||||
${MINIUPNP_DIR}/upnperrors.c
|
||||
${MINIUPNP_DIR}/upnpreplyparse.c
|
||||
${MINIUPNP_DIR}/src/upnpcommands.c
|
||||
${MINIUPNP_DIR}/src/upnpdev.c
|
||||
${MINIUPNP_DIR}/src/upnperrors.c
|
||||
${MINIUPNP_DIR}/src/upnpreplyparse.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h
|
||||
)
|
||||
if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
|
||||
@@ -2601,7 +2671,7 @@ set(WindowsFiles
|
||||
list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser mf uxtheme mfplat mfreadwrite mfuuid shlwapi)
|
||||
list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser dwmapi mf uxtheme mfplat mfreadwrite mfuuid shlwapi)
|
||||
#setup_target_project(${TargetBin} Windows)
|
||||
list(APPEND NativeAppSource ${WindowsFiles})
|
||||
endif()
|
||||
@@ -2755,8 +2825,11 @@ if(TargetBin)
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${BigFontAssets} ${SHADER_FILES} ${THEME_FILE} ${DEBUGGER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Settings.bundle" "ios/Launch Screen.storyboard")
|
||||
file(INSTALL "${CMAKE_SOURCE_DIR}/ext/vulkan/iOS/Frameworks/libMoltenVK.dylib" DESTINATION "${CMAKE_BINARY_DIR}/PPSSPP.app/Frameworks/")
|
||||
set(AssetCatalog "${CMAKE_SOURCE_DIR}/ios/assets.xcassets")
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${BigFontAssets} ${AssetCatalog} ${SHADER_FILES} ${THEME_FILE} ${DEBUGGER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Settings.bundle" "ios/Launch Screen.storyboard")
|
||||
if(NOT IOS_APP_STORE)
|
||||
file(INSTALL "${CMAKE_SOURCE_DIR}/ext/vulkan/iOS/Frameworks/libMoltenVK.dylib" DESTINATION "${CMAKE_BINARY_DIR}/PPSSPP.app/Frameworks/")
|
||||
endif()
|
||||
else()
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${BigFontAssets} ${SHADER_FILES} ${THEME_FILE} ${DEBUGGER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource})
|
||||
file(INSTALL "${CMAKE_SOURCE_DIR}/ext/vulkan/macOS/Frameworks/libMoltenVK.dylib" DESTINATION "${CMAKE_BINARY_DIR}/${TargetBin}.app/Contents/Frameworks/")
|
||||
@@ -2788,7 +2861,11 @@ if(NOT ANDROID)
|
||||
endif()
|
||||
# packaging and code signing
|
||||
if(IOS AND NOT LIBRETRO)
|
||||
set(DEPLOYMENT_TARGET 11.0)
|
||||
if(IOS_APP_STORE)
|
||||
set(DEPLOYMENT_TARGET 12.0)
|
||||
else()
|
||||
set(DEPLOYMENT_TARGET 11.0)
|
||||
endif()
|
||||
file(GLOB IOSAssets ios/assets/*.png)
|
||||
list(REMOVE_ITEM IOSAssets ${CMAKE_CURRENT_SOURCE_DIR}/ios/assets/Default-568h@2x.png)
|
||||
list(REMOVE_ITEM IOSAssets ${CMAKE_CURRENT_SOURCE_DIR}/ios/assets/Default-568h@3x.png)
|
||||
@@ -2798,33 +2875,113 @@ if(IOS AND NOT LIBRETRO)
|
||||
if(IOS_DEBUG)
|
||||
file(INSTALL pspautotests DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/assets)
|
||||
endif()
|
||||
set(RSRC_XIB_FILES assets/Icon@2x.png)
|
||||
set(RSRC_XIB_FILES "Launch Screen.storyboard")
|
||||
set(RSRC_XIB_FILES "Launch Screen.storyboard" ${CMAKE_CURRENT_SOURCE_DIR}/ios/assets.xcassets)
|
||||
|
||||
set_source_files_properties(${RSRC_XIB_FILES}
|
||||
PROPERTIES MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
|
||||
#This breaks in modern XCode. Not sure when it worked...
|
||||
#if(CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
# set(APP_DIR_NAME "$(TARGET_BUILD_DIR)/$(FULL_PRODUCT_NAME)")
|
||||
#else()
|
||||
set(APP_DIR_NAME "$<TARGET_FILE_DIR:PPSSPP>")
|
||||
#endif()
|
||||
add_custom_command(TARGET PPSSPP POST_BUILD
|
||||
COMMAND mkdir -p \"${APP_DIR_NAME}\"
|
||||
COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\"
|
||||
COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/macbundle.sh" \"${APP_DIR_NAME}\"
|
||||
)
|
||||
|
||||
set(MACOSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET})
|
||||
set_target_properties(${TargetBin} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/PPSSPP-Info.plist"
|
||||
RESOURCE "ios/Launch Screen.storyboard"
|
||||
RESOURCE "ios/Settings.bundle"
|
||||
RESOURCE "ext/vulkan/iOS/Frameworks"
|
||||
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "iPhone/iPad"
|
||||
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE NO
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
|
||||
set(PRODUCT_NAME "PPSSPP")
|
||||
set(BUNDLE_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/PPSSPP-Info.plist")
|
||||
if(GOLD)
|
||||
if(IOS_APP_STORE)
|
||||
set(BUNDLE_IDENTIFIER "org.ppsspp.ppsspp-gold")
|
||||
else()
|
||||
set(BUNDLE_IDENTIFIER "org.ppsspp.ppssppgold")
|
||||
endif()
|
||||
set(ICON_NAME "AppIconGold")
|
||||
set(DISPLAY_NAME "PPSSPP Gold")
|
||||
else()
|
||||
if(IOS_APP_STORE)
|
||||
set(BUNDLE_IDENTIFIER "org.ppsspp.ppsspp-free")
|
||||
else()
|
||||
set(BUNDLE_IDENTIFIER "org.ppsspp.ppsspp")
|
||||
endif()
|
||||
set(ICON_NAME "AppIcon")
|
||||
set(DISPLAY_NAME "PPSSPP")
|
||||
endif()
|
||||
if(IOS_APP_STORE)
|
||||
message(STATUS "DevTeam: ${DEVELOPMENT_TEAM_ID} Icon: ${ICON_NAME} Target: ${TargetBin}")
|
||||
message(STATUS "CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
# This is for injecting the version into the plist, and also copying resources.
|
||||
# Should find a different way to do both these things.
|
||||
add_custom_command(TARGET ${TargetBin} POST_BUILD
|
||||
COMMAND echo "Creating ${APP_DIR_NAME} for app store build"
|
||||
COMMAND mkdir -p \"${APP_DIR_NAME}\"
|
||||
# This tar command seems to be responsible for copying assets. I thought we had another step that did that..
|
||||
# Prepend -v to the extracting command to see the files copied.
|
||||
COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\"
|
||||
# This updates the version in the plist.
|
||||
COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/iosbundle.sh" \"${APP_DIR_NAME}\" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# Can't figure out properly using .xcframework from CMake, so just linking directly to the .a file.
|
||||
target_link_libraries(${TargetBin}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/ios/MoltenVK/MoltenVK.xcframework/ios-arm64/libMoltenVK.a"
|
||||
)
|
||||
|
||||
# https://stackoverflow.com/questions/40664125/cmake-and-code-signing-in-xcode-8-for-ios-projects
|
||||
set_target_properties(${TargetBin} PROPERTIES
|
||||
XCODE_GENERATE_SCHEME YES # Avoid the scheme bloat in XCode by only setting it to YES for this target.
|
||||
RESOURCE "ios/Launch Screen.storyboard"
|
||||
RESOURCE "ios/Settings.bundle"
|
||||
RESOURCE "ios/assets.xcassets"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${BUNDLE_IDENTIFIER}
|
||||
XCODE_ATTRIBUTE_PRODUCT_NAME ${PRODUCT_NAME}
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${ICON_NAME}
|
||||
BUILD_WITH_INSTALL_RPATH YES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${BUNDLE_PLIST}
|
||||
# Some sources say we should generate the PLIST. There's stuff in it that
|
||||
# I don't know how to generate, though.
|
||||
#XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE "YES"
|
||||
#XCODE_ATTRIBUTE_INFOPLIST_KEY_UIRequiredDeviceCapabilities arm64
|
||||
XCODE_ATTRIBUTE_INFOPLIST_KEY_UIFileSharingEnabled YES
|
||||
XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY YES
|
||||
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY YES
|
||||
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
|
||||
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE NO
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID}
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic"
|
||||
XCODE_ATTRIBUTE_SKIP_INSTALL NO
|
||||
XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)"
|
||||
)
|
||||
else()
|
||||
# This is for injecting the version into the plist.
|
||||
add_custom_command(TARGET PPSSPP POST_BUILD
|
||||
COMMAND echo "Creating ${APP_DIR_NAME} for sideload build"
|
||||
COMMAND mkdir -p \"${APP_DIR_NAME}\"
|
||||
COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\"
|
||||
COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/macbundle.sh" \"${APP_DIR_NAME}\"
|
||||
)
|
||||
set_target_properties(${TargetBin} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${BUNDLE_PLIST}
|
||||
XCODE_GENERATE_SCHEME YES
|
||||
RESOURCE "ios/Launch Screen.storyboard"
|
||||
RESOURCE "ios/Settings.bundle"
|
||||
RESOURCE "ext/vulkan/iOS/Frameworks"
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${ICON_NAME}
|
||||
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
|
||||
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE NO
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
|
||||
)
|
||||
endif()
|
||||
add_custom_command(TARGET PPSSPP POST_BUILD
|
||||
COMMAND plutil -replace CFBundleDisplayName -string "${DISPLAY_NAME}" "${APP_DIR_NAME}/Info.plist"
|
||||
COMMAND plutil -replace CFBundleIdentifier -string "${BUNDLE_IDENTIFIER}" "${APP_DIR_NAME}/Info.plist"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1041,7 +1041,7 @@ void ARM64XEmitter::QuickCallFunction(ARM64Reg scratchreg, const void *func) {
|
||||
s64 distance = (s64)func - (s64)m_code;
|
||||
distance >>= 2; // Can only branch to opcode-aligned (4) addresses
|
||||
if (!IsInRangeImm26(distance)) {
|
||||
// WARN_LOG(DYNA_REC, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func);
|
||||
// WARN_LOG(Log::JIT, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func);
|
||||
MOVI2R(scratchreg, (uintptr_t)func);
|
||||
BLR(scratchreg);
|
||||
} else {
|
||||
|
||||
+7
-116
@@ -96,7 +96,7 @@ Operand2 AssumeMakeOperand2(u32 imm) {
|
||||
_dbg_assert_msg_(result, "Could not make assumed Operand2.");
|
||||
if (!result) {
|
||||
// Make double sure that we get it logged.
|
||||
ERROR_LOG(JIT, "Could not make assumed Operand2.");
|
||||
ERROR_LOG(Log::JIT, "Could not make assumed Operand2.");
|
||||
}
|
||||
return op2;
|
||||
}
|
||||
@@ -166,7 +166,7 @@ void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate)
|
||||
conv.f = negate ? -val : val;
|
||||
// Try moving directly first if mantisse is empty
|
||||
Operand2 op2;
|
||||
if (cpu_info.bVFPv3 && TryMakeFloatIMM8(conv.u, op2))
|
||||
if (TryMakeFloatIMM8(conv.u, op2))
|
||||
VMOV(dest, op2);
|
||||
else
|
||||
{
|
||||
@@ -182,7 +182,7 @@ void ARMXEmitter::MOVI2F_neon(ARMReg dest, float val, ARMReg tempReg, bool negat
|
||||
conv.f = negate ? -val : val;
|
||||
// Try moving directly first if mantisse is empty
|
||||
Operand2 op2;
|
||||
if (cpu_info.bVFPv3 && TryMakeFloatIMM8(conv.u, op2))
|
||||
if (TryMakeFloatIMM8(conv.u, op2))
|
||||
VMOV_neon(F_32, dest, conv.u);
|
||||
else
|
||||
{
|
||||
@@ -1264,7 +1264,6 @@ void ARMXEmitter::LDMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack,
|
||||
void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_assert_msg_(Vd >= D0, "Pass invalid register to VABD(float)");
|
||||
_assert_msg_(cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it");
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
// Gets encoded as a double register
|
||||
@@ -1279,7 +1278,6 @@ void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_assert_msg_(Vd >= D0, "Pass invalid register to VADD(integer)");
|
||||
_assert_msg_(cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it");
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -1296,7 +1294,6 @@ void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_assert_msg_(Vd >= Q0, "Pass invalid register to VSUB(integer)");
|
||||
_assert_msg_(cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it");
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
@@ -1506,7 +1503,7 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
|
||||
_assert_msg_((imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough");
|
||||
|
||||
if (imm & 0xC03)
|
||||
ERROR_LOG(JIT, "VLDR: Bad offset %08x", imm);
|
||||
ERROR_LOG(Log::JIT, "VLDR: Bad offset %08x", imm);
|
||||
|
||||
bool single_reg = Dest < D0;
|
||||
|
||||
@@ -1534,7 +1531,7 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset)
|
||||
_assert_msg_((imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough");
|
||||
|
||||
if (imm & 0xC03)
|
||||
ERROR_LOG(JIT, "VSTR: Bad offset %08x", imm);
|
||||
ERROR_LOG(Log::JIT, "VSTR: Bad offset %08x", imm);
|
||||
|
||||
bool single_reg = Src < D0;
|
||||
|
||||
@@ -1564,14 +1561,12 @@ void ARMXEmitter::VMSR(ARMReg Rt) {
|
||||
|
||||
void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2)
|
||||
{
|
||||
_assert_msg_(cpu_info.bVFPv3, "VMOV #imm requires VFPv3");
|
||||
int sz = Dest >= D0 ? (1 << 8) : 0;
|
||||
Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (5 << 9) | sz | op2.Imm8VFP());
|
||||
}
|
||||
|
||||
void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm)
|
||||
{
|
||||
_assert_msg_(cpu_info.bNEON, "VMOV_neon #imm requires NEON");
|
||||
_assert_msg_(Vd >= D0, "VMOV_neon #imm must target a double or quad");
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -1656,8 +1651,6 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm)
|
||||
|
||||
void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane)
|
||||
{
|
||||
_assert_msg_(cpu_info.bNEON, "VMOV_neon requires NEON");
|
||||
|
||||
int opc1 = 0;
|
||||
int opc2 = 0;
|
||||
|
||||
@@ -1697,8 +1690,6 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane)
|
||||
|
||||
void ARMXEmitter::VMOV(ARMReg Vd, ARMReg Rt, ARMReg Rt2)
|
||||
{
|
||||
_assert_msg_(cpu_info.bVFP | cpu_info.bNEON, "VMOV_neon requires VFP or NEON");
|
||||
|
||||
if (Vd < S0 && Rt < S0 && Rt2 >= D0)
|
||||
{
|
||||
// Oh, reading to regs, our params are backwards.
|
||||
@@ -1732,7 +1723,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high)
|
||||
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||
{
|
||||
if (Dest == Src) {
|
||||
WARN_LOG(JIT, "VMOV %s, %s - same register", ARMRegAsString(Src), ARMRegAsString(Dest));
|
||||
WARN_LOG(Log::JIT, "VMOV %s, %s - same register", ARMRegAsString(Src), ARMRegAsString(Dest));
|
||||
}
|
||||
if (Dest > R15)
|
||||
{
|
||||
@@ -1787,7 +1778,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||
|
||||
_assert_msg_(SrcSize == DestSize, "VMOV doesn't support moving different register sizes");
|
||||
if (SrcSize != DestSize) {
|
||||
ERROR_LOG(JIT, "SrcSize: %i (%s) DestDize: %i (%s)", SrcSize, ARMRegAsString(Src), DestSize, ARMRegAsString(Dest));
|
||||
ERROR_LOG(Log::JIT, "SrcSize: %i (%s) DestDize: %i (%s)", SrcSize, ARMRegAsString(Src), DestSize, ARMRegAsString(Dest));
|
||||
}
|
||||
|
||||
Dest = SubBase(Dest);
|
||||
@@ -1803,7 +1794,6 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||
// Double and quad
|
||||
if (Quad)
|
||||
{
|
||||
_assert_msg_(cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD.");
|
||||
// Gets encoded as a Double register
|
||||
Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \
|
||||
| ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \
|
||||
@@ -1865,7 +1855,6 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags)
|
||||
void ARMXEmitter::VABA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -1878,7 +1867,6 @@ void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \
|
||||
@@ -1888,7 +1876,6 @@ void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VABD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
if (Size & F_32)
|
||||
@@ -1903,7 +1890,6 @@ void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \
|
||||
@@ -1913,7 +1899,6 @@ void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VABS(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Write32((0xF3 << 24) | (0xB1 << 16) | (encodedSize(Size) << 18) | EncodeVd(Vd) \
|
||||
@@ -1924,7 +1909,6 @@ void ARMXEmitter::VACGE(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
// Only Float
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) \
|
||||
@@ -1935,7 +1919,6 @@ void ARMXEmitter::VACGT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
// Only Float
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) \
|
||||
@@ -1955,7 +1938,6 @@ void ARMXEmitter::VACLT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -1971,7 +1953,6 @@ void ARMXEmitter::VADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \
|
||||
@@ -1983,7 +1964,6 @@ void ARMXEmitter::VADDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \
|
||||
@@ -1994,7 +1974,6 @@ void ARMXEmitter::VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \
|
||||
@@ -2003,7 +1982,6 @@ void ARMXEmitter::VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__);
|
||||
// _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2013,7 +1991,6 @@ void ARMXEmitter::VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2022,7 +1999,6 @@ void ARMXEmitter::VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s: %i", __FUNCTION__, Vd);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
|
||||
@@ -2030,7 +2006,6 @@ void ARMXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2039,7 +2014,6 @@ void ARMXEmitter::VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2048,7 +2022,6 @@ void ARMXEmitter::VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2057,7 +2030,6 @@ void ARMXEmitter::VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
if (Size & F_32)
|
||||
@@ -2070,7 +2042,6 @@ void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2080,7 +2051,6 @@ void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
if (Size & F_32)
|
||||
@@ -2092,7 +2062,6 @@ void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 16) \
|
||||
@@ -2101,7 +2070,6 @@ void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
if (Size & F_32)
|
||||
@@ -2113,7 +2081,6 @@ void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \
|
||||
@@ -2126,7 +2093,6 @@ void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \
|
||||
@@ -2135,7 +2101,6 @@ void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VCLS(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2149,7 +2114,6 @@ void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \
|
||||
@@ -2158,7 +2122,6 @@ void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \
|
||||
@@ -2167,7 +2130,6 @@ void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VCNT(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(Size & I_8, "Can only use I_8 with %s", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2178,7 +2140,6 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Vm, u8 index)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
u32 imm4 = 0;
|
||||
@@ -2195,7 +2156,6 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Rt < S0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Vd = SubBase(Vd);
|
||||
@@ -2213,7 +2173,6 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt)
|
||||
void ARMXEmitter::VEXT(ARMReg Vd, ARMReg Vn, ARMReg Vm, u8 index)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
Write32((0xF2 << 24) | (0xB << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (index & 0xF) \
|
||||
@@ -2223,7 +2182,6 @@ void ARMXEmitter::VFMA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Size == F_32, "Passed invalid size to FP-only NEON instruction");
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2233,7 +2191,6 @@ void ARMXEmitter::VFMS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Size == F_32, "Passed invalid size to FP-only NEON instruction");
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2242,7 +2199,6 @@ void ARMXEmitter::VFMS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2253,7 +2209,6 @@ void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2264,7 +2219,6 @@ void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2277,7 +2231,6 @@ void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2290,7 +2243,6 @@ void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2302,7 +2254,6 @@ void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMLS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2316,7 +2267,6 @@ void ARMXEmitter::VMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \
|
||||
@@ -2327,7 +2277,6 @@ void ARMXEmitter::VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \
|
||||
@@ -2336,7 +2285,6 @@ void ARMXEmitter::VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2349,7 +2297,6 @@ void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2358,7 +2305,6 @@ void ARMXEmitter::VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2374,7 +2320,6 @@ void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2393,7 +2338,6 @@ void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VMVN(ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2404,7 +2348,6 @@ void ARMXEmitter::VMVN(ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2414,7 +2357,6 @@ void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2423,7 +2365,6 @@ void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2433,7 +2374,6 @@ void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2444,7 +2384,6 @@ void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
if (Size & F_32)
|
||||
Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD0 << 4) | EncodeVm(Vm));
|
||||
@@ -2455,7 +2394,6 @@ void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2466,7 +2404,6 @@ void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
if (Size & F_32)
|
||||
Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm));
|
||||
@@ -2477,7 +2414,6 @@ void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
if (Size & F_32)
|
||||
Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm));
|
||||
@@ -2488,7 +2424,6 @@ void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2499,7 +2434,6 @@ void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2510,7 +2444,6 @@ void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2519,7 +2452,6 @@ void ARMXEmitter::VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2528,7 +2460,6 @@ void ARMXEmitter::VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2537,7 +2468,6 @@ void ARMXEmitter::VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2546,7 +2476,6 @@ void ARMXEmitter::VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2557,7 +2486,6 @@ void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF3 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2566,7 +2494,6 @@ void ARMXEmitter::VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2577,7 +2504,6 @@ void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2588,7 +2514,6 @@ void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2599,7 +2524,6 @@ void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2608,7 +2532,6 @@ void ARMXEmitter::VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2618,7 +2541,6 @@ void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2627,7 +2549,6 @@ void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2638,7 +2559,6 @@ void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2649,7 +2569,6 @@ void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
Vd = SubBase(Vd);
|
||||
@@ -2662,7 +2581,6 @@ void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2672,7 +2590,6 @@ void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
@@ -2681,7 +2598,6 @@ void ARMXEmitter::VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VSHL(u32 Size, ARMReg Vd, ARMReg Vm, ARMReg Vn)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
@@ -2710,7 +2626,6 @@ static int EncodeSizeShift(u32 Size, int amount, bool inverse, bool halve) {
|
||||
|
||||
void ARMXEmitter::EncodeShiftByImm(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount, u8 opcode, bool register_quad, bool inverse, bool halve) {
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__);
|
||||
int imm7 = EncodeSizeShift(Size, shiftAmount, inverse, halve);
|
||||
int L = (imm7 >> 6) & 1;
|
||||
@@ -2754,7 +2669,6 @@ void ARMXEmitter::VSHRN(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) {
|
||||
void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2768,7 +2682,6 @@ void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
(0x60 << 4) | EncodeVm(Vm));
|
||||
@@ -2776,7 +2689,6 @@ void ARMXEmitter::VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
(0x20 << 4) | EncodeVm(Vm));
|
||||
@@ -2784,7 +2696,6 @@ void ARMXEmitter::VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
|
||||
(0x30 << 4) | EncodeVm(Vm));
|
||||
@@ -2792,7 +2703,6 @@ void ARMXEmitter::VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2802,7 +2712,6 @@ void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2812,7 +2721,6 @@ void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2822,7 +2730,6 @@ void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2832,7 +2739,6 @@ void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VZIP(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
@@ -2844,7 +2750,6 @@ void ARMXEmitter::VMOVL(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vm >= D0 && Vm <= D31, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOVL");
|
||||
|
||||
bool unsign = (Size & I_UNSIGNED) != 0;
|
||||
@@ -2861,7 +2766,6 @@ void ARMXEmitter::VMOVN(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__);
|
||||
|
||||
// For consistency with assembler syntax and VMOVL - encode one size down.
|
||||
@@ -2874,7 +2778,6 @@ void ARMXEmitter::VQMOVN(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in %s NEON", __FUNCTION__);
|
||||
_dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__);
|
||||
|
||||
@@ -2888,7 +2791,6 @@ void ARMXEmitter::VQMOVUN(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__);
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
_dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__);
|
||||
|
||||
u32 halfSize = encodedSize(Size) - 1;
|
||||
@@ -2940,12 +2842,10 @@ void ARMXEmitter::WriteVLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int reg
|
||||
}
|
||||
|
||||
void ARMXEmitter::VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
WriteVLDST1(true, Size, Vd, Rn, regCount, align, Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
WriteVLDST1(false, Size, Vd, Rn, regCount, align, Rm);
|
||||
}
|
||||
|
||||
@@ -2975,12 +2875,10 @@ void ARMXEmitter::WriteVLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, in
|
||||
}
|
||||
|
||||
void ARMXEmitter::VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
WriteVLDST1_lane(true, Size, Vd, Rn, lane, aligned, Rm);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
WriteVLDST1_lane(false, Size, Vd, Rn, lane, aligned, Rm);
|
||||
}
|
||||
|
||||
@@ -3017,7 +2915,6 @@ void ARMXEmitter::WriteVimm(ARMReg Vd, int cmode, u8 imm, int op) {
|
||||
}
|
||||
|
||||
void ARMXEmitter::VMOV_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// Only let through the modes that apply.
|
||||
switch (type) {
|
||||
case VIMM___x___x:
|
||||
@@ -3054,7 +2951,6 @@ error:
|
||||
}
|
||||
|
||||
void ARMXEmitter::VMOV_immf(ARMReg Vd, float value) { // This only works with a select few values. I've hardcoded 1.0f.
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
u8 bits = 0;
|
||||
|
||||
if (value == 0.0f) {
|
||||
@@ -3076,7 +2972,6 @@ void ARMXEmitter::VMOV_immf(ARMReg Vd, float value) { // This only works with a
|
||||
}
|
||||
|
||||
void ARMXEmitter::VORR_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// Only let through the modes that apply.
|
||||
switch (type) {
|
||||
case VIMM___x___x:
|
||||
@@ -3102,7 +2997,6 @@ error:
|
||||
}
|
||||
|
||||
void ARMXEmitter::VBIC_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// Only let through the modes that apply.
|
||||
switch (type) {
|
||||
case VIMM___x___x:
|
||||
@@ -3129,7 +3023,6 @@ error:
|
||||
|
||||
|
||||
void ARMXEmitter::VMVN_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) {
|
||||
_dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__);
|
||||
// Only let through the modes that apply.
|
||||
switch (type) {
|
||||
case VIMM___x___x:
|
||||
@@ -3187,7 +3080,6 @@ void ARMXEmitter::VREV16(u32 Size, ARMReg Vd, ARMReg Vm)
|
||||
void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) {
|
||||
_assert_msg_(cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4");
|
||||
if (Dest < Q0 || Dest > Q15 || Src < D0 || Src > D15) {
|
||||
_assert_msg_(cpu_info.bNEON, "Bad inputs to VCVTF32F16");
|
||||
// Invalid!
|
||||
}
|
||||
|
||||
@@ -3203,7 +3095,6 @@ void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) {
|
||||
void ARMXEmitter::VCVTF16F32(ARMReg Dest, ARMReg Src) {
|
||||
_assert_msg_(cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4");
|
||||
if (Dest < D0 || Dest > D15 || Src < Q0 || Src > Q15) {
|
||||
_assert_msg_(cpu_info.bNEON, "Bad inputs to VCVTF32F16");
|
||||
// Invalid!
|
||||
}
|
||||
Dest = SubBase(Dest);
|
||||
|
||||
+16
-1
@@ -8,7 +8,21 @@
|
||||
#include <cstddef>
|
||||
#include "CommonTypes.h"
|
||||
|
||||
// Helper functions:
|
||||
// TODO: ARM has an intrinsic for the RBIT instruction in some compilers, __rbit.
|
||||
inline u32 ReverseBits32(u32 v) {
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
|
||||
// swap odd and even bits
|
||||
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
|
||||
// swap consecutive pairs
|
||||
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
|
||||
// swap nibbles ...
|
||||
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
|
||||
// swap bytes
|
||||
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
|
||||
// swap 2-byte long pairs
|
||||
v = (v >> 16) | (v << 16);
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
@@ -35,6 +49,7 @@ inline int LeastSignificantSetBit(u64 val)
|
||||
_BitScanForward64(&index, val);
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
#endif
|
||||
#else
|
||||
inline int CountSetBits(u32 val) { return __builtin_popcount(val); }
|
||||
|
||||
+8
-6
@@ -22,7 +22,9 @@ char *Buffer::Append(size_t length) {
|
||||
|
||||
void Buffer::Append(const std::string &str) {
|
||||
char *ptr = Append(str.size());
|
||||
memcpy(ptr, str.data(), str.size());
|
||||
if (ptr) {
|
||||
memcpy(ptr, str.data(), str.size());
|
||||
}
|
||||
}
|
||||
|
||||
void Buffer::Append(const char *str) {
|
||||
@@ -48,7 +50,7 @@ void Buffer::AppendValue(int value) {
|
||||
|
||||
void Buffer::Take(size_t length, std::string *dest) {
|
||||
if (length > data_.size()) {
|
||||
ERROR_LOG(IO, "Truncating length in Buffer::Take()");
|
||||
ERROR_LOG(Log::IO, "Truncating length in Buffer::Take()");
|
||||
length = data_.size();
|
||||
}
|
||||
dest->resize(length);
|
||||
@@ -77,7 +79,7 @@ int Buffer::TakeLineCRLF(std::string *dest) {
|
||||
|
||||
void Buffer::Skip(size_t length) {
|
||||
if (length > data_.size()) {
|
||||
ERROR_LOG(IO, "Truncating length in Buffer::Skip()");
|
||||
ERROR_LOG(Log::IO, "Truncating length in Buffer::Skip()");
|
||||
length = data_.size();
|
||||
}
|
||||
data_.erase(data_.begin(), data_.begin() + length);
|
||||
@@ -109,10 +111,10 @@ void Buffer::Printf(const char *fmt, ...) {
|
||||
size_t retval = vsnprintf(buffer, sizeof(buffer), fmt, vl);
|
||||
if ((int)retval >= (int)sizeof(buffer)) {
|
||||
// Output was truncated. TODO: Do something.
|
||||
ERROR_LOG(IO, "Buffer::Printf truncated output");
|
||||
ERROR_LOG(Log::IO, "Buffer::Printf truncated output");
|
||||
}
|
||||
if (retval < 0) {
|
||||
ERROR_LOG(IO, "Buffer::Printf failed");
|
||||
if ((int)retval < 0) {
|
||||
ERROR_LOG(Log::IO, "Buffer::Printf failed");
|
||||
}
|
||||
va_end(vl);
|
||||
char *ptr = Append(retval);
|
||||
|
||||
@@ -542,3 +542,31 @@ std::string CPUInfo::Summarize() {
|
||||
}
|
||||
|
||||
#endif // PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
|
||||
|
||||
const char *GetCompilerABI() {
|
||||
#if PPSSPP_ARCH(ARMV7)
|
||||
return "armeabi-v7a";
|
||||
#elif PPSSPP_ARCH(ARM)
|
||||
return "armeabi";
|
||||
#elif PPSSPP_ARCH(ARM64)
|
||||
return "arm64";
|
||||
#elif PPSSPP_ARCH(X86)
|
||||
return "x86";
|
||||
#elif PPSSPP_ARCH(AMD64)
|
||||
return "x86-64";
|
||||
#elif PPSSPP_ARCH(RISCV64)
|
||||
//https://github.com/riscv/riscv-toolchain-conventions#cc-preprocessor-definitions
|
||||
//https://github.com/riscv/riscv-c-api-doc/blob/master/riscv-c-api.md#abi-related-preprocessor-definitions
|
||||
#if defined(__riscv_float_abi_single)
|
||||
return "lp64f";
|
||||
#elif defined(__riscv_float_abi_double)
|
||||
return "lp64d";
|
||||
#elif defined(__riscv_float_abi_quad)
|
||||
return "lp64q";
|
||||
#elif defined(__riscv_float_abi_soft)
|
||||
return "lp64";
|
||||
#endif
|
||||
#else
|
||||
return "other";
|
||||
#endif
|
||||
}
|
||||
@@ -161,3 +161,5 @@ private:
|
||||
};
|
||||
|
||||
extern CPUInfo cpu_info;
|
||||
|
||||
const char *GetCompilerABI();
|
||||
+1
-1
@@ -139,7 +139,7 @@ public:
|
||||
const uint8_t *end = GetCodePtr();
|
||||
size_t sz = end - writeStart_;
|
||||
if (sz > writeEstimated_)
|
||||
WARN_LOG(JIT, "EndWrite(): Estimated %d bytes, wrote %d", (int)writeEstimated_, (int)sz);
|
||||
WARN_LOG(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_)
|
||||
|
||||
+51
-5
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
@@ -385,6 +385,17 @@
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\ext\at3_standalone\at3_decoders.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac3data.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac3plus.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac3plus_data.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\compat.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\fft.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\float_dsp.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\get_bits.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\intreadwrite.h" />
|
||||
<ClInclude Include="..\ext\at3_standalone\mem.h" />
|
||||
<ClInclude Include="..\ext\basis_universal\basisu.h" />
|
||||
<ClInclude Include="..\ext\basis_universal\basisu_containers.h" />
|
||||
<ClInclude Include="..\ext\basis_universal\basisu_containers_impl.h" />
|
||||
@@ -399,6 +410,7 @@
|
||||
<ClInclude Include="..\ext\libpng17\pnglibconf.h" />
|
||||
<ClInclude Include="..\ext\libpng17\pngpriv.h" />
|
||||
<ClInclude Include="..\ext\libpng17\pngstruct.h" />
|
||||
<ClInclude Include="..\ext\minimp3\minimp3.h" />
|
||||
<ClInclude Include="..\ext\naett\naett.h" />
|
||||
<ClInclude Include="..\ext\vma\vk_mem_alloc.h" />
|
||||
<ClInclude Include="ABI.h" />
|
||||
@@ -509,6 +521,16 @@
|
||||
<ClInclude Include="Render\TextureAtlas.h" />
|
||||
<ClInclude Include="Render\Text\draw_text.h" />
|
||||
<ClInclude Include="Render\Text\draw_text_android.h" />
|
||||
<ClInclude Include="Render\Text\draw_text_cocoa.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Render\Text\draw_text_qt.h" />
|
||||
<ClInclude Include="Render\Text\draw_text_sdl.h" />
|
||||
<ClInclude Include="Render\Text\draw_text_uwp.h" />
|
||||
@@ -526,7 +548,8 @@
|
||||
<ClInclude Include="CommonFuncs.h" />
|
||||
<ClInclude Include="CommonTypes.h" />
|
||||
<ClInclude Include="CommonWindows.h" />
|
||||
<ClInclude Include="ConsoleListener.h" />
|
||||
<ClInclude Include="Log\ConsoleListener.h" />
|
||||
<ClInclude Include="Log\StdioListener.h" />
|
||||
<ClInclude Include="CPUDetect.h" />
|
||||
<ClInclude Include="Crypto\md5.h" />
|
||||
<ClInclude Include="Crypto\sha1.h" />
|
||||
@@ -535,7 +558,7 @@
|
||||
<ClInclude Include="ExceptionHandlerSetup.h" />
|
||||
<ClInclude Include="GraphicsContext.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="LogManager.h" />
|
||||
<ClInclude Include="Log\LogManager.h" />
|
||||
<ClInclude Include="MachineContext.h" />
|
||||
<ClInclude Include="MemArena.h" />
|
||||
<ClInclude Include="MemoryUtil.h" />
|
||||
@@ -583,6 +606,15 @@
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3plus.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3plusdec.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3plusdsp.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\get_bits.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\compat.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\fft.cpp" />
|
||||
<ClCompile Include="..\ext\at3_standalone\mem.cpp" />
|
||||
<ClCompile Include="..\ext\basis_universal\basisu_transcoder.cpp" />
|
||||
<ClCompile Include="..\ext\libpng17\png.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
@@ -832,6 +864,7 @@
|
||||
<ForcedIncludeFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</ForcedIncludeFiles>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\minimp3\minimp3.cpp" />
|
||||
<ClCompile Include="..\ext\naett\naett.c" />
|
||||
<ClCompile Include="..\ext\vma\vk_mem_alloc.cpp" />
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
@@ -947,7 +980,8 @@
|
||||
<ClCompile Include="LoongArchCPUDetect.cpp" />
|
||||
<ClCompile Include="Serialize\Serializer.cpp" />
|
||||
<ClCompile Include="Data\Convert\ColorConv.cpp" />
|
||||
<ClCompile Include="ConsoleListener.cpp" />
|
||||
<ClCompile Include="Log\ConsoleListener.cpp" />
|
||||
<ClCompile Include="Log\StdioListener.cpp" />
|
||||
<ClCompile Include="CPUDetect.cpp" />
|
||||
<ClCompile Include="MipsCPUDetect.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
@@ -973,7 +1007,7 @@
|
||||
<ClCompile Include="Crypto\sha1.cpp" />
|
||||
<ClCompile Include="Crypto\sha256.cpp" />
|
||||
<ClCompile Include="ExceptionHandlerSetup.cpp" />
|
||||
<ClCompile Include="LogManager.cpp" />
|
||||
<ClCompile Include="Log\LogManager.cpp" />
|
||||
<ClCompile Include="MemArenaAndroid.cpp" />
|
||||
<ClCompile Include="MemArenaPosix.cpp" />
|
||||
<ClCompile Include="MemArenaWin32.cpp" />
|
||||
@@ -1014,6 +1048,8 @@
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\ext\at3_standalone\CMakeLists.txt" />
|
||||
<Text Include="..\ext\at3_standalone\README.txt" />
|
||||
<Text Include="..\ext\libpng17\CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -1035,6 +1071,16 @@
|
||||
<None Include="..\ext\basis_universal\basisu_transcoder_tables_dxt1_6.inc" />
|
||||
<None Include="..\ext\basis_universal\basisu_transcoder_tables_pvrtc2_45.inc" />
|
||||
<None Include="..\ext\basis_universal\basisu_transcoder_tables_pvrtc2_alpha_33.inc" />
|
||||
<None Include="Render\Text\draw_text_cocoa.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="CommonFuncs.h" />
|
||||
<ClInclude Include="CommonTypes.h" />
|
||||
<ClInclude Include="ConsoleListener.h" />
|
||||
<ClInclude Include="CPUDetect.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="LogManager.h" />
|
||||
<ClInclude Include="MemArena.h" />
|
||||
<ClInclude Include="MemoryUtil.h" />
|
||||
<ClInclude Include="StringUtils.h" />
|
||||
@@ -521,14 +519,59 @@
|
||||
<ClInclude Include="Math\CrossSIMD.h">
|
||||
<Filter>Math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\minimp3\minimp3.h">
|
||||
<Filter>ext\minimp3</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac3data.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac3plus.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac3plus_data.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\atrac.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\get_bits.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\compat.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\fft.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\float_dsp.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\intreadwrite.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\at3_decoders.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ext\at3_standalone\mem.h">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Render\Text\draw_text_cocoa.h">
|
||||
<Filter>Render\Text</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Log\StdioListener.h" />
|
||||
<ClInclude Include="Log\ConsoleListener.h">
|
||||
<Filter>Log</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Log\LogManager.h">
|
||||
<Filter>Log</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
<ClCompile Include="ConsoleListener.cpp" />
|
||||
<ClCompile Include="Log\StdioListener.cpp" />
|
||||
<ClCompile Include="CPUDetect.cpp" />
|
||||
<ClCompile Include="FakeCPUDetect.cpp" />
|
||||
<ClCompile Include="MipsCPUDetect.cpp" />
|
||||
<ClCompile Include="LogManager.cpp" />
|
||||
<ClCompile Include="MemoryUtil.cpp" />
|
||||
<ClCompile Include="StringUtils.cpp" />
|
||||
<ClCompile Include="Thunk.cpp" />
|
||||
@@ -975,6 +1018,42 @@
|
||||
<ClCompile Include="GPU\Vulkan\VulkanDescSet.cpp">
|
||||
<Filter>GPU\Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\minimp3\minimp3.cpp">
|
||||
<Filter>ext\minimp3</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3plus.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3plusdec.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac3plusdsp.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\mem.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\atrac.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\fft.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\get_bits.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ext\at3_standalone\compat.cpp">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Log\ConsoleListener.cpp">
|
||||
<Filter>Log</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Log\LogManager.cpp">
|
||||
<Filter>Log</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Crypto">
|
||||
@@ -1085,11 +1164,26 @@
|
||||
<Filter Include="ext\libchdr">
|
||||
<UniqueIdentifier>{b681797d-7747-487f-b448-5ef5b2d2805b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ext\minimp3">
|
||||
<UniqueIdentifier>{83cd76d0-d1ac-4ed1-9bdc-11fb5a20e5d3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ext\at3_standalone">
|
||||
<UniqueIdentifier>{586da66e-922a-4479-9dac-9d608a1b9183}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Log">
|
||||
<UniqueIdentifier>{cb2c7c09-1177-4a1e-962c-5cc7bcb56789}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\ext\libpng17\CMakeLists.txt">
|
||||
<Filter>ext\libpng17</Filter>
|
||||
</Text>
|
||||
<Text Include="..\ext\at3_standalone\README.txt">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</Text>
|
||||
<Text Include="..\ext\at3_standalone\CMakeLists.txt">
|
||||
<Filter>ext\at3_standalone</Filter>
|
||||
</Text>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\ext\basis_universal\basisu_transcoder_tables_astc.inc">
|
||||
@@ -1122,5 +1216,8 @@
|
||||
<None Include="..\ext\basis_universal\basisu_transcoder_tables_pvrtc2_alpha_33.inc">
|
||||
<Filter>ext\basis_universal</Filter>
|
||||
</None>
|
||||
<None Include="Render\Text\draw_text_cocoa.mm">
|
||||
<Filter>Render\Text</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Common/Log.h"
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
Do(p, size);
|
||||
if (size != N)
|
||||
{
|
||||
ERROR_LOG(COMMON, "Savestate failure: Incompatible queue size.");
|
||||
ERROR_LOG(Log::Common, "Savestate failure: Incompatible queue size.");
|
||||
return;
|
||||
}
|
||||
// TODO: This is quite wasteful, could just store the actual data. Would be slightly more complex though.
|
||||
|
||||
@@ -347,7 +347,7 @@ private:
|
||||
Insert(old[i].hash, old[i].value);
|
||||
}
|
||||
}
|
||||
INFO_LOG(G3D, "Grew hashmap capacity from %d to %d", oldCapacity, capacity_);
|
||||
INFO_LOG(Log::G3D, "Grew hashmap capacity from %d to %d", oldCapacity, capacity_);
|
||||
_assert_msg_(oldCount == count_, "PrehashMap: count should not change in Grow()");
|
||||
}
|
||||
struct Pair {
|
||||
|
||||
@@ -64,26 +64,28 @@ inline u32 RGBA4444ToRGBA8888(u16 src) {
|
||||
const u32 g = (src & 0x00F0) << 4;
|
||||
const u32 b = (src & 0x0F00) << 8;
|
||||
const u32 a = (src & 0xF000) << 12;
|
||||
|
||||
const u32 c = r | g | b | a;
|
||||
return c | (c << 4);
|
||||
}
|
||||
|
||||
inline u32 RGBA5551ToRGBA8888(u16 src) {
|
||||
u8 r = Convert5To8((src >> 0) & 0x1F);
|
||||
u8 g = Convert5To8((src >> 5) & 0x1F);
|
||||
u8 b = Convert5To8((src >> 10) & 0x1F);
|
||||
u8 a = (src >> 15) & 0x1;
|
||||
a = (a) ? 0xff : 0;
|
||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||
u32 dark = ((src & 0x1F) << 3) | ((src & 0x3E0) << 6) | ((src & 0x7C00) << 9);
|
||||
// Replicate the top 3 upper bits into the missing lower bits.
|
||||
u32 full = (dark | ((dark >> 5) & 0x070707));
|
||||
if (src >> 15) {
|
||||
full |= 0xFF000000;
|
||||
}
|
||||
return full;
|
||||
}
|
||||
|
||||
inline u32 RGB565ToRGBA8888(u16 src) {
|
||||
u8 r = Convert5To8((src >> 0) & 0x1F);
|
||||
u8 g = Convert6To8((src >> 5) & 0x3F);
|
||||
u8 b = Convert5To8((src >> 11) & 0x1F);
|
||||
u8 a = 0xFF;
|
||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||
u32 dark_rb = ((src & 0x1F) << 3) | ((src & 0xF800) << 8);
|
||||
// Replicate the top 3 upper bits into the missing lower bits.
|
||||
u32 full_rb = (dark_rb | ((dark_rb >> 5) & 0x070007));
|
||||
// Add in green (6 bits instead of 5).
|
||||
u32 dark_g = ((src & 0x7E0) << 5);
|
||||
u32 full_g = dark_g | ((dark_g >> 6) & 0x300);
|
||||
return full_rb | full_g | 0xFF000000;
|
||||
}
|
||||
|
||||
inline u16 RGBA8888ToRGB565(u32 value) {
|
||||
|
||||
@@ -20,7 +20,7 @@ bool compress_string(const std::string& str, std::string *dest, int compressionl
|
||||
memset(&zs, 0, sizeof(zs));
|
||||
|
||||
if (deflateInit(&zs, compressionlevel) != Z_OK) {
|
||||
ERROR_LOG(IO, "deflateInit failed while compressing.");
|
||||
ERROR_LOG(Log::IO, "deflateInit failed while compressing.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ bool decompress_string(const std::string& str, std::string *dest) {
|
||||
|
||||
// modification by hrydgard: inflateInit2, 16+MAXWBITS makes it read gzip data too
|
||||
if (inflateInit2(&zs, 32+MAX_WBITS) != Z_OK) {
|
||||
ERROR_LOG(IO, "inflateInit failed while decompressing.");
|
||||
ERROR_LOG(Log::IO, "inflateInit failed while decompressing.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ bool decompress_string(const std::string& str, std::string *dest) {
|
||||
inflateEnd(&zs);
|
||||
|
||||
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
|
||||
ERROR_LOG(IO, "Exception during zlib decompression: (%i) %s", ret, zs.msg);
|
||||
ERROR_LOG(Log::IO, "Exception during zlib decompression: (%i) %s", ret, zs.msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/Data/Encoding/Utf16.h"
|
||||
#include "Common/Log.h"
|
||||
|
||||
// is start of UTF sequence
|
||||
inline bool isutf(char c) {
|
||||
@@ -209,6 +210,7 @@ int u8_charnum(const char *s, int offset)
|
||||
/* reads the next utf-8 sequence out of a string, updating an index */
|
||||
uint32_t u8_nextchar(const char *s, int *index, size_t size) {
|
||||
uint32_t ch = 0;
|
||||
_dbg_assert_(*index >= 0 && *index < 100000000);
|
||||
int sz = 0;
|
||||
int i = *index;
|
||||
do {
|
||||
@@ -372,8 +374,6 @@ int u8_is_locale_utf8(const char *locale)
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTF8::UTF8(const char *c) : c_(c), size_((int)strlen(c)), index_(0) {}
|
||||
|
||||
bool AnyEmojiInString(std::string_view str, size_t byteCount) {
|
||||
int i = 0;
|
||||
while (i < byteCount) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -39,7 +40,7 @@ class UTF8 {
|
||||
public:
|
||||
static const uint32_t INVALID = (uint32_t)-1;
|
||||
// TODO: Try to get rid of this constructor.
|
||||
explicit UTF8(const char *c);
|
||||
explicit UTF8(const char *c) : c_(c), size_((int)strlen(c)), index_(0) {}
|
||||
explicit UTF8(std::string_view view) : c_(view.data()), size_((int)view.size()), index_(0) {}
|
||||
explicit UTF8(std::string_view view, int index) : c_(view.data()), size_((int)view.size()), index_(index) {}
|
||||
bool end() const { return index_ == size_; }
|
||||
|
||||
@@ -198,7 +198,7 @@ bool Section::GetKeys(std::vector<std::string> &keys) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
ParsedIniLine *Section::GetLine(const char *key) {
|
||||
ParsedIniLine *Section::GetLine(std::string_view key) {
|
||||
for (auto &line : lines_) {
|
||||
if (equalsNoCase(line.Key(), key))
|
||||
return &line;
|
||||
@@ -206,7 +206,7 @@ ParsedIniLine *Section::GetLine(const char *key) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ParsedIniLine *Section::GetLine(const char* key) const {
|
||||
const ParsedIniLine *Section::GetLine(std::string_view key) const {
|
||||
for (auto &line : lines_) {
|
||||
if (equalsNoCase(line.Key(), key))
|
||||
return &line;
|
||||
@@ -214,38 +214,38 @@ const ParsedIniLine *Section::GetLine(const char* key) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, uint32_t newValue) {
|
||||
void Section::Set(std::string_view key, uint32_t newValue) {
|
||||
char temp[128];
|
||||
snprintf(temp, sizeof(temp), "0x%08x", newValue);
|
||||
Set(key, (const char *)temp);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, uint64_t newValue) {
|
||||
void Section::Set(std::string_view key, uint64_t newValue) {
|
||||
char temp[128];
|
||||
snprintf(temp, sizeof(temp), "0x%016" PRIx64, newValue);
|
||||
Set(key, (const char *)temp);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, float newValue) {
|
||||
void Section::Set(std::string_view key, float newValue) {
|
||||
_dbg_assert_(!my_isnanorinf(newValue));
|
||||
char temp[128];
|
||||
snprintf(temp, sizeof(temp), "%f", newValue);
|
||||
Set(key, (const char *)temp);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, double newValue) {
|
||||
void Section::Set(std::string_view key, double newValue) {
|
||||
char temp[128];
|
||||
snprintf(temp, sizeof(temp), "%f", newValue);
|
||||
Set(key, (const char *)temp);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, int newValue) {
|
||||
void Section::Set(std::string_view key, int newValue) {
|
||||
char temp[128];
|
||||
snprintf(temp, sizeof(temp), "%d", newValue);
|
||||
Set(key, (const char *)temp);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, const char* newValue) {
|
||||
void Section::Set(std::string_view key, const char* newValue) {
|
||||
ParsedIniLine *line = GetLine(key);
|
||||
if (line) {
|
||||
line->SetValue(newValue);
|
||||
@@ -255,7 +255,7 @@ void Section::Set(const char* key, const char* newValue) {
|
||||
}
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, const std::string& newValue, const std::string& defaultValue)
|
||||
void Section::Set(std::string_view key, const std::string& newValue, const std::string& defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
Set(key, newValue);
|
||||
@@ -263,7 +263,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) const {
|
||||
bool Section::Get(std::string_view key, std::string* value, const char* defaultValue) const {
|
||||
const ParsedIniLine *line = GetLine(key);
|
||||
if (!line) {
|
||||
if (defaultValue) {
|
||||
@@ -276,7 +276,7 @@ bool Section::Get(const char* key, std::string* value, const char* defaultValue)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, const float newValue, const float defaultValue)
|
||||
void Section::Set(std::string_view key, const float newValue, const float defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
Set(key, newValue);
|
||||
@@ -284,7 +284,7 @@ void Section::Set(const char* key, const float newValue, const float defaultValu
|
||||
Delete(key);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, int newValue, int defaultValue)
|
||||
void Section::Set(std::string_view key, int newValue, int defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
Set(key, newValue);
|
||||
@@ -292,7 +292,7 @@ void Section::Set(const char* key, int newValue, int defaultValue)
|
||||
Delete(key);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, bool newValue, bool defaultValue)
|
||||
void Section::Set(std::string_view key, bool newValue, bool defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
Set(key, newValue);
|
||||
@@ -300,7 +300,7 @@ void Section::Set(const char* key, bool newValue, bool defaultValue)
|
||||
Delete(key);
|
||||
}
|
||||
|
||||
void Section::Set(const char* key, const std::vector<std::string>& newValues)
|
||||
void Section::Set(std::string_view key, const std::vector<std::string>& newValues)
|
||||
{
|
||||
std::string temp;
|
||||
// Join the strings with ,
|
||||
@@ -319,36 +319,32 @@ void Section::AddComment(const std::string &comment) {
|
||||
lines_.emplace_back(ParsedIniLine::CommentOnly("# " + comment));
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, std::vector<std::string>& values) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, std::vector<std::string>& values) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (!retval || temp.empty())
|
||||
{
|
||||
if (!retval || temp.empty()) {
|
||||
return false;
|
||||
}
|
||||
// ignore starting , if any
|
||||
size_t subStart = temp.find_first_not_of(",");
|
||||
size_t subStart = temp.find_first_not_of(',');
|
||||
size_t subEnd;
|
||||
|
||||
// split by ,
|
||||
while (subStart != std::string::npos) {
|
||||
|
||||
// Find next ,
|
||||
subEnd = temp.find_first_of(",", subStart);
|
||||
subEnd = temp.find_first_of(',', subStart);
|
||||
if (subStart != subEnd)
|
||||
// take from first char until next ,
|
||||
values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));
|
||||
|
||||
// Find the next non , char
|
||||
subStart = temp.find_first_not_of(",", subEnd);
|
||||
subStart = temp.find_first_not_of(',', subEnd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, int* value, int defaultValue) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, int* value, int defaultValue) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (retval && TryParse(temp, value))
|
||||
@@ -357,8 +353,7 @@ bool Section::Get(const char* key, int* value, int defaultValue) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, uint32_t* value, uint32_t defaultValue) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (retval && TryParse(temp, value))
|
||||
@@ -367,8 +362,7 @@ bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, uint64_t* value, uint64_t defaultValue) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (retval && TryParse(temp, value))
|
||||
@@ -377,8 +371,7 @@ bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, bool* value, bool defaultValue) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, bool* value, bool defaultValue) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (retval && TryParse(temp, value))
|
||||
@@ -387,8 +380,7 @@ bool Section::Get(const char* key, bool* value, bool defaultValue) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, float* value, float defaultValue) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, float* value, float defaultValue) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (retval && TryParse(temp, value))
|
||||
@@ -397,8 +389,7 @@ bool Section::Get(const char* key, float* value, float defaultValue) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const char* key, double* value, double defaultValue) const
|
||||
{
|
||||
bool Section::Get(std::string_view key, double* value, double defaultValue) const {
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
if (retval && TryParse(temp, value))
|
||||
@@ -407,7 +398,7 @@ bool Section::Get(const char* key, double* value, double defaultValue) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Exists(const char *key) const {
|
||||
bool Section::Exists(std::string_view key) const {
|
||||
for (auto &line : lines_) {
|
||||
if (equalsNoCase(key, line.Key()))
|
||||
return true;
|
||||
@@ -425,7 +416,7 @@ std::map<std::string, std::string> Section::ToMap() const {
|
||||
return outMap;
|
||||
}
|
||||
|
||||
bool Section::Delete(const char *key) {
|
||||
bool Section::Delete(std::string_view key) {
|
||||
ParsedIniLine *line = GetLine(key);
|
||||
for (auto liter = lines_.begin(); liter != lines_.end(); ++liter) {
|
||||
if (line == &*liter) {
|
||||
|
||||
@@ -54,56 +54,56 @@ class Section {
|
||||
|
||||
public:
|
||||
Section() {}
|
||||
Section(const std::string& name) : name_(name) {}
|
||||
Section(std::string_view name) : name_(name) {}
|
||||
|
||||
bool Exists(const char *key) const;
|
||||
bool Delete(const char *key);
|
||||
bool Exists(std::string_view key) const;
|
||||
bool Delete(std::string_view key);
|
||||
|
||||
void Clear();
|
||||
|
||||
std::map<std::string, std::string> ToMap() const;
|
||||
|
||||
ParsedIniLine *GetLine(const char *key);
|
||||
const ParsedIniLine *GetLine(const char *key) const;
|
||||
ParsedIniLine *GetLine(std::string_view key);
|
||||
const ParsedIniLine *GetLine(std::string_view key) const;
|
||||
|
||||
void Set(const char* key, const char* newValue);
|
||||
void Set(const char* key, const std::string& newValue, const std::string& defaultValue);
|
||||
void Set(std::string_view key, const char* newValue);
|
||||
void Set(std::string_view 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());
|
||||
void Set(std::string_view key, const std::string &value) {
|
||||
Set(key, value.c_str());
|
||||
}
|
||||
bool Get(const char* key, std::string* value, const char* defaultValue) const;
|
||||
bool Get(std::string_view key, std::string* value, const char* defaultValue) const;
|
||||
|
||||
void Set(const char* key, uint32_t newValue);
|
||||
void Set(const char* key, uint64_t newValue);
|
||||
void Set(const char* key, float newValue);
|
||||
void Set(const char* key, const float newValue, const float defaultValue);
|
||||
void Set(const char* key, double newValue);
|
||||
void Set(std::string_view key, uint32_t newValue);
|
||||
void Set(std::string_view key, uint64_t newValue);
|
||||
void Set(std::string_view key, float newValue);
|
||||
void Set(std::string_view key, const float newValue, const float defaultValue);
|
||||
void Set(std::string_view key, double newValue);
|
||||
|
||||
void Set(const char* key, int newValue, int defaultValue);
|
||||
void Set(const char* key, int newValue);
|
||||
void Set(std::string_view key, int newValue, int defaultValue);
|
||||
void Set(std::string_view key, int newValue);
|
||||
|
||||
void Set(const char* key, bool newValue, bool defaultValue);
|
||||
void Set(const char* key, bool newValue) {
|
||||
void Set(std::string_view key, bool newValue, bool defaultValue);
|
||||
void Set(std::string_view key, bool newValue) {
|
||||
Set(key, newValue ? "True" : "False");
|
||||
}
|
||||
void Set(const char* key, const std::vector<std::string>& newValues);
|
||||
void Set(std::string_view key, const std::vector<std::string>& newValues);
|
||||
|
||||
// Declare without a body to make it fail to compile. This is to prevent accidentally
|
||||
// setting a pointer as a bool. The failure is in the linker unfortunately, but that's better
|
||||
// than accidentally succeeding in a bad way.
|
||||
template<class T>
|
||||
void Set(const char *key, T *ptr);
|
||||
void Set(std::string_view key, T *ptr);
|
||||
|
||||
void AddComment(const std::string &comment);
|
||||
|
||||
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<std::string>& values) const;
|
||||
bool Get(std::string_view key, int* value, int defaultValue = 0) const;
|
||||
bool Get(std::string_view key, uint32_t* value, uint32_t defaultValue = 0) const;
|
||||
bool Get(std::string_view key, uint64_t* value, uint64_t defaultValue = 0) const;
|
||||
bool Get(std::string_view key, bool* value, bool defaultValue = false) const;
|
||||
bool Get(std::string_view key, float* value, float defaultValue = false) const;
|
||||
bool Get(std::string_view key, double* value, double defaultValue = false) const;
|
||||
bool Get(std::string_view key, std::vector<std::string>& values) const;
|
||||
|
||||
// Return a list of all keys in this section
|
||||
bool GetKeys(std::vector<std::string> &keys) const;
|
||||
@@ -133,30 +133,7 @@ public:
|
||||
// Returns true if key exists in section
|
||||
bool Exists(const char* sectionName, const char* key) const;
|
||||
|
||||
// TODO: Get rid of these, in favor of the Section ones.
|
||||
void Set(const char* sectionName, const char* key, const char* newValue) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValue);
|
||||
}
|
||||
void Set(const char* sectionName, const char* key, const std::string& newValue) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValue.c_str());
|
||||
}
|
||||
void Set(const char* sectionName, const char* key, int newValue) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValue);
|
||||
}
|
||||
void Set(const char* sectionName, const char* key, uint32_t newValue) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValue);
|
||||
}
|
||||
void Set(const char* sectionName, const char* key, uint64_t newValue) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValue);
|
||||
}
|
||||
void Set(const char* sectionName, const char* key, bool newValue) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValue);
|
||||
}
|
||||
void Set(const char* sectionName, const char* key, const std::vector<std::string>& newValues) {
|
||||
GetOrCreateSection(sectionName)->Set(key, newValues);
|
||||
}
|
||||
|
||||
// TODO: Get rid of these, in favor of the Section ones.
|
||||
// These will not create the section if it doesn't exist.
|
||||
bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = "");
|
||||
bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0);
|
||||
bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0);
|
||||
@@ -164,13 +141,6 @@ public:
|
||||
bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false);
|
||||
bool Get(const char* sectionName, const char* key, std::vector<std::string>& values);
|
||||
|
||||
template<typename T> bool GetIfExists(const char* sectionName, const char* key, T value)
|
||||
{
|
||||
if (Exists(sectionName, key))
|
||||
return Get(sectionName, key, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetKeys(const char* sectionName, std::vector<std::string>& keys) const;
|
||||
|
||||
bool DeleteKey(const char* sectionName, const char* key);
|
||||
@@ -180,13 +150,12 @@ public:
|
||||
|
||||
std::vector<std::unique_ptr<Section>> &Sections() { return sections; }
|
||||
|
||||
bool HasSection(const char *section) { return GetSection(section) != 0; }
|
||||
bool HasSection(const char *section) { return GetSection(section) != nullptr; }
|
||||
const Section* GetSection(const char* section) const;
|
||||
Section* GetSection(const char* section);
|
||||
|
||||
Section* GetOrCreateSection(const char* section);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Section>> sections;
|
||||
|
||||
const Section* GetSection(const char* section) const;
|
||||
Section* GetSection(const char* section);
|
||||
};
|
||||
@@ -17,7 +17,7 @@ JsonReader::JsonReader(const std::string &filename) {
|
||||
if (buffer_) {
|
||||
parse();
|
||||
} else {
|
||||
ERROR_LOG(IO, "Failed to read json file '%s'", filename.c_str());
|
||||
ERROR_LOG(Log::IO, "Failed to read json file '%s'", filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ bool JsonReader::parse() {
|
||||
char *error_pos;
|
||||
int status = jsonParse(buffer_, &error_pos, &root_, alloc_);
|
||||
if (status != JSON_OK) {
|
||||
ERROR_LOG(IO, "Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos);
|
||||
ERROR_LOG(Log::IO, "Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos);
|
||||
return false;
|
||||
}
|
||||
ok_ = true;
|
||||
@@ -46,7 +46,7 @@ int JsonGet::numChildren() const {
|
||||
|
||||
const JsonNode *JsonGet::get(const char *child_name) const {
|
||||
if (!child_name) {
|
||||
ERROR_LOG(IO, "JSON: Cannot get from null child name");
|
||||
ERROR_LOG(Log::IO, "JSON: Cannot get from null child name");
|
||||
return nullptr;
|
||||
}
|
||||
if (value_.getTag() != JSON_OBJECT) {
|
||||
@@ -71,7 +71,7 @@ const char *JsonGet::getStringOrNull(const char *child_name) const {
|
||||
const JsonNode *val = get(child_name, JSON_STRING);
|
||||
if (val)
|
||||
return val->value.toString();
|
||||
ERROR_LOG(IO, "String '%s' missing from node", child_name);
|
||||
ERROR_LOG(Log::IO, "String '%s' missing from node", child_name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_d
|
||||
|
||||
if (PNG_IMAGE_FAILED(png))
|
||||
{
|
||||
WARN_LOG(IO, "pngLoad: %s (%s)", png.message, file);
|
||||
WARN_LOG(Log::IO, "pngLoad: %s (%s)", png.message, file);
|
||||
*image_data_ptr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, in
|
||||
png_image_begin_read_from_memory(&png, input_ptr, input_len);
|
||||
|
||||
if (PNG_IMAGE_FAILED(png)) {
|
||||
WARN_LOG(IO, "pngLoad: %s", png.message);
|
||||
WARN_LOG(Log::IO, "pngLoad: %s", png.message);
|
||||
*image_data_ptr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, in
|
||||
|
||||
size_t size = PNG_IMAGE_SIZE(png);
|
||||
if (!size) {
|
||||
ERROR_LOG(IO, "pngLoad: empty image");
|
||||
ERROR_LOG(Log::IO, "pngLoad: empty image");
|
||||
*image_data_ptr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,11 +21,12 @@ RIFFReader::~RIFFReader() {
|
||||
}
|
||||
|
||||
int RIFFReader::ReadInt() {
|
||||
int value = 0;
|
||||
if (data_ && pos_ < eof_ - 3) {
|
||||
pos_ += 4;
|
||||
return *(int *)(data_ + pos_ - 4);
|
||||
memcpy(&value, data_ + pos_ - 4, 4);
|
||||
}
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool RIFFReader::Descend(uint32_t intoId) {
|
||||
@@ -46,7 +47,7 @@ bool RIFFReader::Descend(uint32_t intoId) {
|
||||
int startLocation = pos_;
|
||||
|
||||
if (pos_ + length > fileSize_) {
|
||||
ERROR_LOG(IO, "Block extends outside of RIFF file - failing descend");
|
||||
ERROR_LOG(Log::IO, "Block extends outside of RIFF file - failing descend");
|
||||
pos_ = stack[depth_].parentStartLocation;
|
||||
return false;
|
||||
}
|
||||
@@ -61,7 +62,7 @@ bool RIFFReader::Descend(uint32_t intoId) {
|
||||
if (length > 0) {
|
||||
pos_ += length; // try next block
|
||||
} else {
|
||||
ERROR_LOG(IO, "Bad data in RIFF file : block length %d. Not descending.", length);
|
||||
ERROR_LOG(Log::IO, "Bad data in RIFF file : block length %d. Not descending.", length);
|
||||
pos_ = stack[depth_].parentStartLocation;
|
||||
return false;
|
||||
}
|
||||
@@ -104,4 +105,3 @@ int RIFFReader::GetCurrentChunkSize() {
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSr
|
||||
|
||||
int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int *flags, uint8_t **image) {
|
||||
if (zim[0] != 'Z' || zim[1] != 'I' || zim[2] != 'M' || zim[3] != 'G') {
|
||||
ERROR_LOG(IO, "Not a ZIM file");
|
||||
ERROR_LOG(Log::IO, "Not a ZIM file");
|
||||
return 0;
|
||||
}
|
||||
memcpy(width, zim + 4, 4);
|
||||
@@ -78,14 +78,14 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int
|
||||
image_data_size[i] = width[i] * height[i] * 2;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(IO, "Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK);
|
||||
ERROR_LOG(Log::IO, "Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK);
|
||||
return 0;
|
||||
}
|
||||
total_data_size += image_data_size[i];
|
||||
}
|
||||
|
||||
if (total_data_size == 0) {
|
||||
ERROR_LOG(IO, "Invalid ZIM data size 0");
|
||||
ERROR_LOG(Log::IO, "Invalid ZIM data size 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -98,19 +98,19 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int
|
||||
long outlen = (long)total_data_size;
|
||||
int retcode = ezuncompress(*image, &outlen, (unsigned char *)(zim + 16), (long)datasize - 16);
|
||||
if (Z_OK != retcode) {
|
||||
ERROR_LOG(IO, "ZIM zlib format decompression failed: %d", retcode);
|
||||
ERROR_LOG(Log::IO, "ZIM zlib format decompression failed: %d", retcode);
|
||||
free(*image);
|
||||
*image = 0;
|
||||
return 0;
|
||||
}
|
||||
if (outlen != total_data_size) {
|
||||
// Shouldn't happen if return value was Z_OK.
|
||||
ERROR_LOG(IO, "Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size);
|
||||
ERROR_LOG(Log::IO, "Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size);
|
||||
}
|
||||
} else if (*flags & ZIM_ZSTD_COMPRESSED) {
|
||||
size_t outlen = ZSTD_decompress(*image, total_data_size, zim + 16, datasize - 16);
|
||||
if (outlen != (size_t)total_data_size) {
|
||||
ERROR_LOG(IO, "ZIM zstd format decompression failed: %lld", (long long)outlen);
|
||||
ERROR_LOG(Log::IO, "ZIM zstd format decompression failed: %lld", (long long)outlen);
|
||||
free(*image);
|
||||
*image = 0;
|
||||
return 0;
|
||||
@@ -118,7 +118,7 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int
|
||||
} else {
|
||||
memcpy(*image, zim + 16, datasize - 16);
|
||||
if (datasize - 16 != (size_t)total_data_size) {
|
||||
ERROR_LOG(IO, "Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size);
|
||||
ERROR_LOG(Log::IO, "Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size);
|
||||
}
|
||||
}
|
||||
return num_levels;
|
||||
@@ -128,13 +128,13 @@ int LoadZIM(const char *filename, int *width, int *height, int *format, uint8_t
|
||||
size_t size;
|
||||
uint8_t *buffer = g_VFS.ReadFile(filename, &size);
|
||||
if (!buffer) {
|
||||
ERROR_LOG(IO, "Couldn't read data for '%s'", filename);
|
||||
ERROR_LOG(Log::IO, "Couldn't read data for '%s'", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retval = LoadZIMPtr(buffer, size, width, height, format, image);
|
||||
if (!retval) {
|
||||
ERROR_LOG(IO, "Not a valid ZIM file: %s (size: %lld bytes)", filename, (long long)size);
|
||||
ERROR_LOG(Log::IO, "Not a valid ZIM file: %s (size: %lld bytes)", filename, (long long)size);
|
||||
}
|
||||
delete [] buffer;
|
||||
return retval;
|
||||
|
||||
@@ -143,7 +143,7 @@ void Convert(const uint8_t *image_data, int width, int height, int pitch, int fl
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(IO, "Unhandled ZIM format %d", flags & ZIM_FORMAT_MASK);
|
||||
ERROR_LOG(Log::IO, "Unhandled ZIM format %d", flags & ZIM_FORMAT_MASK);
|
||||
*data = 0;
|
||||
*data_size = 0;
|
||||
return;
|
||||
@@ -199,7 +199,7 @@ void SaveZIM(FILE *f, int width, int height, int pitch, int flags, const uint8_t
|
||||
if (Z_OK == ezcompress(dest, &dest_len, data, data_size, compressLevel == 0 ? Z_DEFAULT_COMPRESSION : compressLevel)) {
|
||||
fwrite(dest, 1, dest_len, f);
|
||||
} else {
|
||||
ERROR_LOG(IO, "Zlib compression failed.\n");
|
||||
ERROR_LOG(Log::IO, "Zlib compression failed.\n");
|
||||
}
|
||||
delete [] dest;
|
||||
} else if (flags & ZIM_ZSTD_COMPRESSED) {
|
||||
@@ -209,7 +209,7 @@ void SaveZIM(FILE *f, int width, int height, int pitch, int flags, const uint8_t
|
||||
if (!ZSTD_isError(dest_len)) {
|
||||
fwrite(dest, 1, dest_len, f);
|
||||
} else {
|
||||
ERROR_LOG(IO, "Zlib compression failed.\n");
|
||||
ERROR_LOG(Log::IO, "Zlib compression failed.\n");
|
||||
}
|
||||
delete [] dest;
|
||||
} else {
|
||||
|
||||
@@ -112,6 +112,11 @@ void I18NCategory::SetMap(const std::map<std::string, std::string> &m) {
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> I18NCategory::Missed() const {
|
||||
std::lock_guard<std::mutex> guard(missedKeyLock_);
|
||||
return missedKeyLog_;
|
||||
}
|
||||
|
||||
std::shared_ptr<I18NCategory> I18NRepo::GetCategory(I18NCat category) {
|
||||
std::lock_guard<std::mutex> guard(catsLock_);
|
||||
if (category != I18NCat::NONE)
|
||||
@@ -137,7 +142,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const Path &overridePath)
|
||||
IniFile ini;
|
||||
Path iniPath;
|
||||
|
||||
// INFO_LOG(SYSTEM, "Loading lang ini %s", iniPath.c_str());
|
||||
// INFO_LOG(Log::System, "Loading lang ini %s", iniPath.c_str());
|
||||
if (!overridePath.empty()) {
|
||||
iniPath = overridePath / (languageID + ".ini");
|
||||
} else {
|
||||
@@ -169,7 +174,7 @@ void I18NRepo::LogMissingKeys() const {
|
||||
for (size_t i = 0; i < (size_t)I18NCat::CATEGORY_COUNT; i++) {
|
||||
auto &cat = cats_[i];
|
||||
for (auto &key : cat->Missed()) {
|
||||
INFO_LOG(SYSTEM, "Missing translation [%s]: %s (%s)", g_categoryNames[i], key.first.c_str(), key.second.c_str());
|
||||
INFO_LOG(Log::System, "Missing translation [%s]: %s (%s)", g_categoryNames[i], key.first.c_str(), key.second.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-13
@@ -64,19 +64,12 @@ enum class I18NCat : uint8_t {
|
||||
};
|
||||
|
||||
struct I18NEntry {
|
||||
I18NEntry(const std::string &t) : text(t), readFlag(false) {}
|
||||
I18NEntry(std::string_view t) : text(t), readFlag(false) {}
|
||||
I18NEntry() : readFlag(false) {}
|
||||
std::string text;
|
||||
bool readFlag;
|
||||
};
|
||||
|
||||
struct I18NCandidate {
|
||||
I18NCandidate() : key(0), defVal(0) {}
|
||||
I18NCandidate(const char *k, const char *d) : key(k), defVal(d) {}
|
||||
const char *key;
|
||||
const char *defVal;
|
||||
};
|
||||
|
||||
class I18NCategory {
|
||||
public:
|
||||
I18NCategory() {}
|
||||
@@ -88,10 +81,7 @@ public:
|
||||
// Try to avoid this. Still useful in snprintf.
|
||||
const char *T_cstr(const char *key, const char *def = nullptr);
|
||||
|
||||
std::map<std::string, std::string> Missed() const {
|
||||
std::lock_guard<std::mutex> guard(missedKeyLock_);
|
||||
return missedKeyLog_;
|
||||
}
|
||||
std::map<std::string, std::string> Missed() const;
|
||||
|
||||
const std::map<std::string, I18NEntry, std::less<>> &GetMap() { return map_; }
|
||||
void ClearMissed() { missedKeyLog_.clear(); }
|
||||
@@ -155,4 +145,4 @@ inline std::string_view T(I18NCat category, std::string_view key, std::string_vi
|
||||
|
||||
inline const char *T_cstr(I18NCat category, const char *key, const char *def = "") {
|
||||
return g_i18nrepo.T_cstr(category, key, def);
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) {
|
||||
|
||||
// This will include the newline.
|
||||
if (x_ <= maxW_) {
|
||||
out_.append(str_ + lastWordStartIndex, str_ + endIndex);
|
||||
out_.append(str_.data() + lastWordStartIndex, str_.data() + endIndex);
|
||||
} else {
|
||||
scanForNewline_ = true;
|
||||
}
|
||||
@@ -153,7 +153,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) {
|
||||
x_ = 0.0f;
|
||||
} else {
|
||||
// We may have appended a newline - check.
|
||||
size_t pos = out_.find_last_of("\n");
|
||||
size_t pos = out_.find_last_of('\n');
|
||||
if (pos != out_.npos) {
|
||||
lastLineStart_ = pos + 1;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) {
|
||||
|
||||
if (lastLineStart_ != out_.size()) {
|
||||
// To account for kerning around spaces, we recalculate the entire line width.
|
||||
x_ = MeasureWidth(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_);
|
||||
x_ = MeasureWidth(std::string_view(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_));
|
||||
} else {
|
||||
x_ = 0.0f;
|
||||
}
|
||||
@@ -178,10 +178,10 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) {
|
||||
|
||||
void WordWrapper::Wrap() {
|
||||
// First, let's check if it fits as-is.
|
||||
size_t len = strlen(str_);
|
||||
if (MeasureWidth(str_, len) <= maxW_) {
|
||||
size_t len = str_.length();
|
||||
if (MeasureWidth(str_) <= maxW_) {
|
||||
// If it fits, we don't need to go through each character.
|
||||
out_ = str_;
|
||||
out_ = std::string(str_);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ void WordWrapper::Wrap() {
|
||||
out_.reserve(len + len / 16);
|
||||
|
||||
if (flags_ & FLAG_ELLIPSIZE_TEXT) {
|
||||
ellipsisWidth_ = MeasureWidth("...", 3);
|
||||
ellipsisWidth_ = MeasureWidth("...");
|
||||
}
|
||||
|
||||
for (UTF8 utf(str_); !utf.end(); ) {
|
||||
@@ -219,7 +219,10 @@ void WordWrapper::Wrap() {
|
||||
}
|
||||
|
||||
// Measure the entire word for kerning purposes. May not be 100% perfect.
|
||||
float newWordWidth = MeasureWidth(str_ + lastIndex_, afterIndex - lastIndex_);
|
||||
float newWordWidth = 0.0f;
|
||||
if (afterIndex <= str_.length()) {
|
||||
newWordWidth = MeasureWidth(str_.substr(lastIndex_, afterIndex - lastIndex_));
|
||||
}
|
||||
|
||||
// Is this the end of a word (space)? We'll also output up to a soft hyphen.
|
||||
if (wordWidth_ > 0.0f && IsSpaceOrShy(c)) {
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class WordWrapper {
|
||||
public:
|
||||
WordWrapper(const char *str, float maxW, int flags)
|
||||
WordWrapper(std::string_view str, float maxW, int flags)
|
||||
: str_(str), maxW_(maxW), flags_(flags) {
|
||||
}
|
||||
virtual ~WordWrapper() {}
|
||||
|
||||
// TODO: This should return a vector of std::string_view for the lines, instead of building up a new string.
|
||||
std::string Wrapped();
|
||||
|
||||
protected:
|
||||
virtual float MeasureWidth(const char *str, size_t bytes) = 0;
|
||||
virtual float MeasureWidth(std::string_view str) = 0;
|
||||
|
||||
void Wrap();
|
||||
bool WrapBeforeWord();
|
||||
void AppendWord(int endIndex, int lastChar, bool addNewline);
|
||||
@@ -26,7 +29,7 @@ protected:
|
||||
return IsSpace(c) || IsShy(c);
|
||||
}
|
||||
|
||||
const char *const str_;
|
||||
const std::string_view str_;
|
||||
const float maxW_;
|
||||
const int flags_;
|
||||
std::string out_;
|
||||
|
||||
@@ -81,7 +81,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(SYSTEM, "Installing exception handler");
|
||||
INFO_LOG(Log::System, "Installing exception handler");
|
||||
g_badAccessHandler = badAccessHandler;
|
||||
g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, GlobalExceptionHandler);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||
void UninstallExceptionHandler() {
|
||||
if (g_vectoredExceptionHandle) {
|
||||
RemoveVectoredExceptionHandler(g_vectoredExceptionHandle);
|
||||
INFO_LOG(SYSTEM, "Removed exception handler");
|
||||
INFO_LOG(Log::System, "Removed exception handler");
|
||||
g_vectoredExceptionHandle = nullptr;
|
||||
}
|
||||
g_badAccessHandler = nullptr;
|
||||
@@ -186,7 +186,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||
}
|
||||
g_badAccessHandler = badAccessHandler;
|
||||
|
||||
INFO_LOG(SYSTEM, "Installing exception handler");
|
||||
INFO_LOG(Log::System, "Installing exception handler");
|
||||
mach_port_t port;
|
||||
CheckKR("mach_port_allocate",
|
||||
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port));
|
||||
@@ -290,7 +290,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||
// Add some extra room.
|
||||
altStackSize += 65536;
|
||||
|
||||
INFO_LOG(SYSTEM, "Installed exception handler. stack size: %d", (int)altStackSize);
|
||||
INFO_LOG(Log::System, "Installed exception handler. stack size: %d", (int)altStackSize);
|
||||
g_badAccessHandler = badAccessHandler;
|
||||
|
||||
stack_t signal_stack{};
|
||||
@@ -323,7 +323,7 @@ void UninstallExceptionHandler() {
|
||||
stack_t signal_stack{};
|
||||
signal_stack.ss_flags = SS_DISABLE;
|
||||
if (0 != sigaltstack(&signal_stack, nullptr)) {
|
||||
ERROR_LOG(SYSTEM, "Could not remove signal altstack");
|
||||
ERROR_LOG(Log::System, "Could not remove signal altstack");
|
||||
}
|
||||
if (altStack) {
|
||||
free(altStack);
|
||||
@@ -333,7 +333,7 @@ void UninstallExceptionHandler() {
|
||||
#ifdef __APPLE__
|
||||
sigaction(SIGBUS, &old_sa_bus, nullptr);
|
||||
#endif
|
||||
INFO_LOG(SYSTEM, "Uninstalled exception handler");
|
||||
INFO_LOG(Log::System, "Uninstalled exception handler");
|
||||
g_badAccessHandler = nullptr;
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ void UninstallExceptionHandler() {
|
||||
#else // !MACHINE_CONTEXT_SUPPORTED
|
||||
|
||||
void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||
ERROR_LOG(SYSTEM, "Exception handler not implemented on this platform, can't install");
|
||||
ERROR_LOG(Log::System, "Exception handler not implemented on this platform, can't install");
|
||||
}
|
||||
void UninstallExceptionHandler() { }
|
||||
|
||||
|
||||
@@ -145,26 +145,26 @@ public:
|
||||
return Type;
|
||||
}
|
||||
Operand2() {}
|
||||
Operand2(u32 imm, OpType type = TYPE_IMM)
|
||||
Operand2(u32 imm, OpType type = TYPE_IMM) : IndexOrShift(), Shift()
|
||||
{
|
||||
Type = type;
|
||||
Value = imm;
|
||||
Rotation = 0;
|
||||
}
|
||||
|
||||
Operand2(FakeReg Reg)
|
||||
Operand2(FakeReg Reg) : IndexOrShift(), Shift()
|
||||
{
|
||||
Type = TYPE_REG;
|
||||
Value = Reg;
|
||||
Rotation = 0;
|
||||
}
|
||||
Operand2(u8 imm, u8 rotation)
|
||||
Operand2(u8 imm, u8 rotation) : IndexOrShift(), Shift()
|
||||
{
|
||||
Type = TYPE_IMM;
|
||||
Value = imm;
|
||||
Rotation = rotation;
|
||||
}
|
||||
Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR
|
||||
Operand2(FakeReg base, ShiftType type, FakeReg shift) : Rotation(0) // RSR
|
||||
{
|
||||
Type = TYPE_RSR;
|
||||
_assert_msg_(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
Value = base;
|
||||
}
|
||||
|
||||
Operand2(FakeReg base, ShiftType type, u8 shift)// For IMM shifted register
|
||||
Operand2(FakeReg base, ShiftType type, u8 shift) : Rotation(0) // For IMM shifted register
|
||||
{
|
||||
if(shift == 32) shift = 0;
|
||||
switch (type)
|
||||
|
||||
@@ -48,7 +48,7 @@ bool AndroidContentURI::Parse(std::string_view path) {
|
||||
|
||||
AndroidContentURI AndroidContentURI::WithRootFilePath(const std::string &filePath) {
|
||||
if (root.empty()) {
|
||||
ERROR_LOG(SYSTEM, "WithRootFilePath cannot be used with single file URIs.");
|
||||
ERROR_LOG(Log::System, "WithRootFilePath cannot be used with single file URIs.");
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -114,9 +114,9 @@ bool AndroidContentURI::CanNavigateUp() const {
|
||||
// Only goes downwards in hierarchies. No ".." will ever be generated.
|
||||
bool AndroidContentURI::ComputePathTo(const AndroidContentURI &other, std::string &path) const {
|
||||
size_t offset = FilePath().size() + 1;
|
||||
std::string otherFilePath = other.FilePath();
|
||||
const auto &otherFilePath = other.FilePath();
|
||||
if (offset >= otherFilePath.size()) {
|
||||
ERROR_LOG(SYSTEM, "Bad call to PathTo. '%s' -> '%s'", FilePath().c_str(), other.FilePath().c_str());
|
||||
ERROR_LOG(Log::System, "Bad call to PathTo. '%s' -> '%s'", FilePath().c_str(), other.FilePath().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -125,11 +125,11 @@ bool AndroidContentURI::ComputePathTo(const AndroidContentURI &other, std::strin
|
||||
}
|
||||
|
||||
std::string AndroidContentURI::GetFileExtension() const {
|
||||
size_t pos = file.rfind(".");
|
||||
size_t pos = file.rfind('.');
|
||||
if (pos == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
size_t slash_pos = file.rfind("/");
|
||||
size_t slash_pos = file.rfind('/');
|
||||
if (slash_pos != std::string::npos && slash_pos > pos) {
|
||||
// Don't want to detect "df/file" from "/as.df/file"
|
||||
return "";
|
||||
|
||||
@@ -67,6 +67,10 @@ public:
|
||||
return root.empty() ? file : root;
|
||||
}
|
||||
|
||||
const std::string &Provider() const {
|
||||
return provider;
|
||||
}
|
||||
|
||||
bool IsTreeURI() const {
|
||||
return !root.empty();
|
||||
}
|
||||
|
||||
@@ -154,20 +154,26 @@ static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) {
|
||||
std::vector<std::string> parts;
|
||||
SplitString(line, '|', parts);
|
||||
if (parts.size() != 4) {
|
||||
ERROR_LOG(FILESYS, "Bad format: %s", line.c_str());
|
||||
ERROR_LOG(Log::FileSystem, "Bad format (1): %s", line.c_str());
|
||||
return false;
|
||||
}
|
||||
fileInfo->name = std::string(parts[2]);
|
||||
fileInfo->isDirectory = parts[0][0] == 'D';
|
||||
fileInfo->exists = true;
|
||||
sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size);
|
||||
if (1 != sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size)) {
|
||||
ERROR_LOG(Log::FileSystem, "Bad format (2): %s", line.c_str());
|
||||
return false;
|
||||
}
|
||||
fileInfo->isWritable = true; // TODO: Should be passed as part of the string.
|
||||
// TODO: For read-only mappings, reflect that here, similarly as with isWritable.
|
||||
// Directories are normally executable (0111) which means they're traversable.
|
||||
fileInfo->access = fileInfo->isDirectory ? 0777 : 0666;
|
||||
|
||||
uint64_t lastModifiedMs = 0;
|
||||
sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs);
|
||||
if (1 != sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs)) {
|
||||
ERROR_LOG(Log::FileSystem, "Bad format (3): %s", line.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert from milliseconds
|
||||
uint32_t lastModified = lastModifiedMs / 1000;
|
||||
@@ -229,7 +235,7 @@ std::vector<File::FileInfo> Android_ListContentUri(const std::string &path, bool
|
||||
const char *charArray = env->GetStringUTFChars(str, 0);
|
||||
if (charArray) { // paranoia
|
||||
std::string line = charArray;
|
||||
File::FileInfo info;
|
||||
File::FileInfo info{};
|
||||
if (line == "X") {
|
||||
// Indicates an exception thrown, path doesn't exist.
|
||||
*exists = false;
|
||||
@@ -247,7 +253,7 @@ std::vector<File::FileInfo> Android_ListContentUri(const std::string &path, bool
|
||||
double elapsed = time_now_d() - start;
|
||||
double threshold = 0.1;
|
||||
if (elapsed >= threshold) {
|
||||
INFO_LOG(FILESYS, "Listing directory on content URI '%s' took %0.3f s (%d files, log threshold = %0.3f)", path.c_str(), elapsed, (int)items.size(), threshold);
|
||||
INFO_LOG(Log::FileSystem, "Listing directory on content URI '%s' took %0.3f s (%d files, log threshold = %0.3f)", path.c_str(), elapsed, (int)items.size(), threshold);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
@@ -284,7 +290,7 @@ int64_t Android_ComputeRecursiveDirectorySize(const std::string &uri) {
|
||||
int64_t size = env->CallLongMethod(g_nativeActivity, computeRecursiveDirectorySize, param);
|
||||
double elapsed = time_now_d() - start;
|
||||
|
||||
INFO_LOG(IO, "ComputeRecursiveDirectorySize(%s) in %0.3f s", uri.c_str(), elapsed);
|
||||
INFO_LOG(Log::IO, "ComputeRecursiveDirectorySize(%s) in %0.3f s", uri.c_str(), elapsed);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ bool free_disk_space(const Path &path, int64_t &space) {
|
||||
#else
|
||||
if (path.Type() == PathType::CONTENT_URI) {
|
||||
space = Android_GetFreeSpaceByContentUri(path.ToString());
|
||||
INFO_LOG(COMMON, "Free space at '%s': %" PRIu64, path.c_str(), space);
|
||||
INFO_LOG(Log::Common, "Free space at '%s': %" PRIu64, path.c_str(), space);
|
||||
return space >= 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ void SetNonBlocking(int sock, bool non_blocking) {
|
||||
int opts = fcntl(sock, F_GETFL);
|
||||
if (opts < 0) {
|
||||
perror("fcntl(F_GETFL)");
|
||||
ERROR_LOG(IO, "Error getting socket status while changing nonblocking status");
|
||||
ERROR_LOG(Log::IO, "Error getting socket status while changing nonblocking status");
|
||||
}
|
||||
if (non_blocking) {
|
||||
opts = (opts | O_NONBLOCK);
|
||||
@@ -124,12 +124,12 @@ void SetNonBlocking(int sock, bool non_blocking) {
|
||||
|
||||
if (fcntl(sock, F_SETFL, opts) < 0) {
|
||||
perror("fcntl(F_SETFL)");
|
||||
ERROR_LOG(IO, "Error setting socket nonblocking status");
|
||||
ERROR_LOG(Log::IO, "Error setting socket nonblocking status");
|
||||
}
|
||||
#else
|
||||
u_long val = non_blocking ? 1 : 0;
|
||||
if (ioctlsocket(sock, FIONBIO, &val) != 0) {
|
||||
ERROR_LOG(IO, "Error setting socket nonblocking status");
|
||||
ERROR_LOG(Log::IO, "Error setting socket nonblocking status");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+128
-70
@@ -20,6 +20,9 @@
|
||||
#ifndef UNICODE
|
||||
#error Win32 build requires a unicode build
|
||||
#endif
|
||||
#else
|
||||
#define _POSIX_SOURCE
|
||||
#define _LARGE_TIME_API
|
||||
#endif
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
@@ -37,6 +40,8 @@
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/LogReporting.h"
|
||||
#include "Common/File/AndroidContentURI.h"
|
||||
@@ -46,6 +51,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Common/CommonWindows.h"
|
||||
#include <sys/utime.h>
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h> // for SHGetFolderPath
|
||||
#include <shellapi.h>
|
||||
@@ -63,6 +69,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
|
||||
@@ -110,7 +117,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
|
||||
case PathType::CONTENT_URI:
|
||||
// We're gonna need some error codes..
|
||||
if (!strcmp(mode, "r") || !strcmp(mode, "rb") || !strcmp(mode, "rt")) {
|
||||
INFO_LOG(COMMON, "Opening content file for read: '%s'", path.c_str());
|
||||
INFO_LOG(Log::Common, "Opening content file for read: '%s'", path.c_str());
|
||||
// Read, let's support this - easy one.
|
||||
int descriptor = Android_OpenContentUriFd(path.ToString(), Android_OpenContentUriMode::READ);
|
||||
if (descriptor < 0) {
|
||||
@@ -121,20 +128,20 @@ FILE *OpenCFile(const Path &path, const char *mode) {
|
||||
// Need to be able to create the file here if it doesn't exist.
|
||||
// Not exactly sure which abstractions are best, let's start simple.
|
||||
if (!File::Exists(path)) {
|
||||
INFO_LOG(COMMON, "OpenCFile(%s): Opening content file for write. Doesn't exist, creating empty and reopening.", path.c_str());
|
||||
INFO_LOG(Log::Common, "OpenCFile(%s): Opening content file for write. Doesn't exist, creating empty and reopening.", path.c_str());
|
||||
std::string name = path.GetFilename();
|
||||
if (path.CanNavigateUp()) {
|
||||
Path parent = path.NavigateUp();
|
||||
if (Android_CreateFile(parent.ToString(), name) != StorageError::SUCCESS) {
|
||||
WARN_LOG(COMMON, "Failed to create file '%s' in '%s'", name.c_str(), parent.c_str());
|
||||
WARN_LOG(Log::Common, "Failed to create file '%s' in '%s'", name.c_str(), parent.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
INFO_LOG_REPORT_ONCE(openCFileFailedNavigateUp, COMMON, "Failed to navigate up to create file: %s", path.c_str());
|
||||
INFO_LOG_REPORT_ONCE(openCFileFailedNavigateUp, Log::Common, "Failed to navigate up to create file: %s", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
INFO_LOG(COMMON, "OpenCFile(%s): Opening existing content file for write (truncating). Requested mode: '%s'", path.c_str(), mode);
|
||||
INFO_LOG(Log::Common, "OpenCFile(%s): Opening existing content file for write (truncating). Requested mode: '%s'", path.c_str(), mode);
|
||||
}
|
||||
|
||||
// TODO: Support append modes and stuff... For now let's go with the most common one.
|
||||
@@ -146,7 +153,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
|
||||
}
|
||||
int descriptor = Android_OpenContentUriFd(path.ToString(), openMode);
|
||||
if (descriptor < 0) {
|
||||
INFO_LOG(COMMON, "Opening '%s' for write failed", path.ToString().c_str());
|
||||
INFO_LOG(Log::Common, "Opening '%s' for write failed", path.ToString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
FILE *f = fdopen(descriptor, fmode);
|
||||
@@ -156,18 +163,18 @@ FILE *OpenCFile(const Path &path, const char *mode) {
|
||||
}
|
||||
return f;
|
||||
} else {
|
||||
ERROR_LOG(COMMON, "OpenCFile(%s): Mode not yet supported: %s", path.c_str(), mode);
|
||||
ERROR_LOG(Log::Common, "OpenCFile(%s): Mode not yet supported: %s", path.c_str(), mode);
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(COMMON, "OpenCFile(%s): PathType not yet supported", path.c_str());
|
||||
ERROR_LOG(Log::Common, "OpenCFile(%s): PathType not yet supported", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
#if PPSSPP_PLATFORM(UWP) && !defined(__LIBRETRO__)
|
||||
// We shouldn't use _wfopen here,
|
||||
// We shouldn't use _wfopen here,
|
||||
// this function is not allowed to read outside Local and Installation folders
|
||||
// FileSystem (broadFileSystemAccess) doesn't apply on _wfopen
|
||||
// if we have custom memory stick location _wfopen will return null
|
||||
@@ -206,27 +213,27 @@ int OpenFD(const Path &path, OpenFlag flags) {
|
||||
case PathType::CONTENT_URI:
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(COMMON, "OpenFD: Only supports Content URI paths. Not '%s' (%s)!", path.c_str(), OpenFlagToString(flags).c_str());
|
||||
ERROR_LOG(Log::Common, "OpenFD: Only supports Content URI paths. Not '%s' (%s)!", path.c_str(), OpenFlagToString(flags).c_str());
|
||||
// Not yet supported - use other paths.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & OPEN_CREATE) {
|
||||
if (!File::Exists(path)) {
|
||||
INFO_LOG(COMMON, "OpenFD(%s): Creating file.", path.c_str());
|
||||
INFO_LOG(Log::Common, "OpenFD(%s): Creating file.", path.c_str());
|
||||
std::string name = path.GetFilename();
|
||||
if (path.CanNavigateUp()) {
|
||||
Path parent = path.NavigateUp();
|
||||
if (Android_CreateFile(parent.ToString(), name) != StorageError::SUCCESS) {
|
||||
WARN_LOG(COMMON, "OpenFD: Failed to create file '%s' in '%s'", name.c_str(), parent.c_str());
|
||||
WARN_LOG(Log::Common, "OpenFD: Failed to create file '%s' in '%s'", name.c_str(), parent.c_str());
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
INFO_LOG(COMMON, "Failed to navigate up to create file: %s", path.c_str());
|
||||
INFO_LOG(Log::Common, "Failed to navigate up to create file: %s", path.c_str());
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
INFO_LOG(COMMON, "OpenCFile(%s): Opening existing content file ('%s')", path.c_str(), OpenFlagToString(flags).c_str());
|
||||
INFO_LOG(Log::Common, "OpenCFile(%s): Opening existing content file ('%s')", path.c_str(), OpenFlagToString(flags).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,14 +249,14 @@ int OpenFD(const Path &path, OpenFlag flags) {
|
||||
// TODO: Maybe better checking of additional flags here.
|
||||
} else {
|
||||
// TODO: Add support for more modes if possible.
|
||||
ERROR_LOG_REPORT_ONCE(openFlagNotSupported, COMMON, "OpenFlag %s not yet supported", OpenFlagToString(flags).c_str());
|
||||
ERROR_LOG_REPORT_ONCE(openFlagNotSupported, Log::Common, "OpenFlag %s not yet supported", OpenFlagToString(flags).c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "Android_OpenContentUriFd: %s (%s)", path.c_str(), OpenFlagToString(flags).c_str());
|
||||
INFO_LOG(Log::Common, "Android_OpenContentUriFd: %s (%s)", path.c_str(), OpenFlagToString(flags).c_str());
|
||||
int descriptor = Android_OpenContentUriFd(path.ToString(), mode);
|
||||
if (descriptor < 0) {
|
||||
ERROR_LOG(COMMON, "Android_OpenContentUriFd failed: '%s'", path.c_str());
|
||||
ERROR_LOG(Log::Common, "Android_OpenContentUriFd failed: '%s'", path.c_str());
|
||||
}
|
||||
|
||||
if (flags & OPEN_APPEND) {
|
||||
@@ -340,6 +347,9 @@ std::string ResolvePath(const std::string &path) {
|
||||
delete [] buf;
|
||||
return output;
|
||||
|
||||
#elif PPSSPP_PLATFORM(IOS)
|
||||
// Resolving has wacky effects on documents paths.
|
||||
return path;
|
||||
#else
|
||||
std::unique_ptr<char[]> buf(new char[PATH_MAX + 32768]);
|
||||
if (realpath(path.c_str(), buf.get()) == nullptr)
|
||||
@@ -404,8 +414,8 @@ bool Exists(const Path &path) {
|
||||
SetErrorMode(OldMode);
|
||||
#endif
|
||||
return true;
|
||||
#else
|
||||
struct stat file_info;
|
||||
#else // !WIN32
|
||||
struct stat file_info{};
|
||||
return stat(path.c_str(), &file_info) == 0;
|
||||
#endif
|
||||
}
|
||||
@@ -436,7 +446,7 @@ bool IsDirectory(const Path &filename) {
|
||||
#endif
|
||||
auto err = GetLastError();
|
||||
if (err != ERROR_FILE_NOT_FOUND) {
|
||||
WARN_LOG(COMMON, "GetFileAttributes failed on %s: %08x %s", filename.ToVisualString().c_str(), (uint32_t)err, GetStringErrorMsg(err).c_str());
|
||||
WARN_LOG(Log::Common, "GetFileAttributes failed on %s: %08x %s", filename.ToVisualString().c_str(), (uint32_t)err, GetStringErrorMsg(err).c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -447,7 +457,7 @@ bool IsDirectory(const Path &filename) {
|
||||
struct stat file_info;
|
||||
int result = stat(copy.c_str(), &file_info);
|
||||
if (result < 0) {
|
||||
WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", copy.c_str(), GetLastErrorMsg().c_str());
|
||||
WARN_LOG(Log::Common, "IsDirectory: stat failed on %s: %s", copy.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
return S_ISDIR(file_info.st_mode);
|
||||
@@ -466,36 +476,36 @@ bool Delete(const Path &filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "Delete: file %s", filename.c_str());
|
||||
INFO_LOG(Log::Common, "Delete: file %s", filename.c_str());
|
||||
|
||||
// Return true because we care about the file no
|
||||
// Return true because we care about the file no
|
||||
// being there, not the actual delete.
|
||||
if (!Exists(filename)) {
|
||||
WARN_LOG(COMMON, "Delete: '%s' already does not exist", filename.c_str());
|
||||
WARN_LOG(Log::Common, "Delete: '%s' already does not exist", filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can't delete a directory
|
||||
if (IsDirectory(filename)) {
|
||||
WARN_LOG(COMMON, "Delete failed: '%s' is a directory", filename.c_str());
|
||||
WARN_LOG(Log::Common, "Delete failed: '%s' is a directory", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
if (!DeleteFileFromAppW(filename.ToWString().c_str())) {
|
||||
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str());
|
||||
WARN_LOG(Log::Common, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (!DeleteFile(filename.ToWString().c_str())) {
|
||||
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str());
|
||||
WARN_LOG(Log::Common, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (unlink(filename.c_str()) == -1) {
|
||||
WARN_LOG(COMMON, "Delete: unlink failed on %s: %s",
|
||||
WARN_LOG(Log::Common, "Delete: unlink failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -522,11 +532,11 @@ bool CreateDir(const Path &path) {
|
||||
AndroidContentURI uri(path.ToString());
|
||||
std::string newDirName = uri.GetLastPart();
|
||||
if (uri.NavigateUp()) {
|
||||
INFO_LOG(COMMON, "Calling Android_CreateDirectory(%s, %s)", uri.ToString().c_str(), newDirName.c_str());
|
||||
INFO_LOG(Log::Common, "Calling Android_CreateDirectory(%s, %s)", uri.ToString().c_str(), newDirName.c_str());
|
||||
return Android_CreateDirectory(uri.ToString(), newDirName) == StorageError::SUCCESS;
|
||||
} else {
|
||||
// Bad path - can't create this directory.
|
||||
WARN_LOG(COMMON, "CreateDir failed: '%s'", path.c_str());
|
||||
WARN_LOG(Log::Common, "CreateDir failed: '%s'", path.c_str());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -535,7 +545,7 @@ bool CreateDir(const Path &path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(COMMON, "CreateDir('%s')", path.c_str());
|
||||
DEBUG_LOG(Log::Common, "CreateDir('%s')", path.c_str());
|
||||
#ifdef _WIN32
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
if (CreateDirectoryFromAppW(path.ToWString().c_str(), NULL))
|
||||
@@ -544,13 +554,13 @@ bool CreateDir(const Path &path) {
|
||||
if (::CreateDirectory(path.ToWString().c_str(), NULL))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ALREADY_EXISTS) {
|
||||
WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
|
||||
WARN_LOG(Log::Common, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
|
||||
return true;
|
||||
}
|
||||
ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %08x %s", path.c_str(), (uint32_t)error, GetStringErrorMsg(error).c_str());
|
||||
ERROR_LOG(Log::Common, "CreateDir: CreateDirectory failed on %s: %08x %s", path.c_str(), (uint32_t)error, GetStringErrorMsg(error).c_str());
|
||||
return false;
|
||||
#else
|
||||
if (mkdir(path.ToString().c_str(), 0755) == 0) {
|
||||
@@ -559,11 +569,11 @@ bool CreateDir(const Path &path) {
|
||||
|
||||
int err = errno;
|
||||
if (err == EEXIST) {
|
||||
WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
|
||||
WARN_LOG(Log::Common, "CreateDir: mkdir failed on %s: already exists", path.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
|
||||
ERROR_LOG(Log::Common, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -571,7 +581,7 @@ bool CreateDir(const Path &path) {
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const Path &path) {
|
||||
if (File::Exists(path)) {
|
||||
DEBUG_LOG(COMMON, "CreateFullPath: path exists %s", path.c_str());
|
||||
DEBUG_LOG(Log::Common, "CreateFullPath: path exists %s", path.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -580,7 +590,7 @@ bool CreateFullPath(const Path &path) {
|
||||
case PathType::CONTENT_URI:
|
||||
break; // OK
|
||||
default:
|
||||
ERROR_LOG(COMMON, "CreateFullPath(%s): Not yet supported", path.c_str());
|
||||
ERROR_LOG(Log::Common, "CreateFullPath(%s): Not yet supported", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -598,7 +608,7 @@ bool CreateFullPath(const Path &path) {
|
||||
|
||||
// Probably not necessary sanity check, ported from the old code.
|
||||
if (parts.size() > 100) {
|
||||
ERROR_LOG(COMMON, "CreateFullPath: directory structure too deep");
|
||||
ERROR_LOG(Log::Common, "CreateFullPath: directory structure too deep");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -613,7 +623,7 @@ bool CreateFullPath(const Path &path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const Path &srcFilename, const Path &destFilename) {
|
||||
if (srcFilename.Type() != destFilename.Type()) {
|
||||
// Impossible. You're gonna need to make a copy, and delete the original. Not the responsibility
|
||||
@@ -630,16 +640,16 @@ bool Rename(const Path &srcFilename, const Path &destFilename) {
|
||||
// Content URI: Can only rename if in the same folder.
|
||||
// TODO: Fallback to move + rename? Or do we even care about that use case? We have MoveIfFast for such tricks.
|
||||
if (srcFilename.GetDirectory() != destFilename.GetDirectory()) {
|
||||
INFO_LOG(COMMON, "Content URI rename: Directories not matching, failing. %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
INFO_LOG(Log::Common, "Content URI rename: Directories not matching, failing. %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(COMMON, "Content URI rename: %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
INFO_LOG(Log::Common, "Content URI rename: %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
return Android_RenameFileTo(srcFilename.ToString(), destFilename.GetFilename()) == StorageError::SUCCESS;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
INFO_LOG(Log::Common, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
@@ -656,12 +666,12 @@ bool Rename(const Path &srcFilename, const Path &destFilename) {
|
||||
return true;
|
||||
#endif
|
||||
|
||||
ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
|
||||
ERROR_LOG(Log::Common, "Rename: failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
switch (srcFilename.Type()) {
|
||||
case PathType::NATIVE:
|
||||
@@ -673,6 +683,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
if (Android_CopyFile(srcFilename.ToString(), destParent.ToString()) == StorageError::SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
INFO_LOG(Log::Common, "Android_CopyFile failed, falling back.");
|
||||
// Else fall through, and try using file I/O.
|
||||
}
|
||||
break;
|
||||
@@ -680,7 +691,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
INFO_LOG(Log::Common, "Copy by OpenCFile: %s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
#ifdef _WIN32
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
if (CopyFileFromAppW(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str(), FALSE))
|
||||
@@ -689,10 +700,10 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
if (CopyFile(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str(), FALSE))
|
||||
return true;
|
||||
#endif
|
||||
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
|
||||
ERROR_LOG(Log::Common, "Copy: failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
#else
|
||||
#else // Non-Win32
|
||||
|
||||
// buffer size
|
||||
#define BSIZE 16384
|
||||
@@ -702,7 +713,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
// Open input file
|
||||
FILE *input = OpenCFile(srcFilename, "rb");
|
||||
if (!input) {
|
||||
ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s",
|
||||
ERROR_LOG(Log::Common, "Copy: input failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -711,22 +722,24 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
FILE *output = OpenCFile(destFilename, "wb");
|
||||
if (!output) {
|
||||
fclose(input);
|
||||
ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s",
|
||||
ERROR_LOG(Log::Common, "Copy: output failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int bytesWritten = 0;
|
||||
|
||||
// copy loop
|
||||
while (!feof(input)) {
|
||||
// read input
|
||||
int rnum = fread(buffer, sizeof(char), BSIZE, input);
|
||||
if (rnum != BSIZE) {
|
||||
if (ferror(input) != 0) {
|
||||
ERROR_LOG(COMMON,
|
||||
"Copy: failed reading from source, %s --> %s: %s",
|
||||
ERROR_LOG(Log::Common,
|
||||
"Copy: failed reading from source, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
fclose(output);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -734,14 +747,21 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
|
||||
// write output
|
||||
int wnum = fwrite(buffer, sizeof(char), rnum, output);
|
||||
if (wnum != rnum) {
|
||||
ERROR_LOG(COMMON,
|
||||
"Copy: failed writing to output, %s --> %s: %s",
|
||||
ERROR_LOG(Log::Common,
|
||||
"Copy: failed writing to output, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
fclose(output);
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten += wnum;
|
||||
}
|
||||
|
||||
if (bytesWritten == 0) {
|
||||
WARN_LOG(Log::Common, "Copy: No bytes written (must mean that input was empty)");
|
||||
}
|
||||
|
||||
// close flushes
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
@@ -826,14 +846,14 @@ uint64_t GetFileSize(const Path &filename) {
|
||||
int result = stat64(filename.c_str(), &file_info);
|
||||
#endif
|
||||
if (result != 0) {
|
||||
WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.ToVisualString().c_str());
|
||||
WARN_LOG(Log::Common, "GetSize: failed %s: No such file", filename.ToVisualString().c_str());
|
||||
return 0;
|
||||
}
|
||||
if (S_ISDIR(file_info.st_mode)) {
|
||||
WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.ToVisualString().c_str());
|
||||
WARN_LOG(Log::Common, "GetSize: failed %s: is a directory", filename.ToVisualString().c_str());
|
||||
return 0;
|
||||
}
|
||||
DEBUG_LOG(COMMON, "GetSize: %s: %lld", filename.ToVisualString().c_str(), (long long)file_info.st_size);
|
||||
DEBUG_LOG(Log::Common, "GetSize: %s: %lld", filename.ToVisualString().c_str(), (long long)file_info.st_size);
|
||||
return file_info.st_size;
|
||||
#endif
|
||||
}
|
||||
@@ -880,12 +900,12 @@ uint64_t GetFileSize(FILE *f) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const Path &filename) {
|
||||
INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
|
||||
INFO_LOG(Log::Common, "CreateEmptyFile: %s", filename.c_str());
|
||||
FILE *pFile = OpenCFile(filename, "wb");
|
||||
if (!pFile) {
|
||||
ERROR_LOG(COMMON, "CreateEmptyFile: failed to create '%s': %s", filename.c_str(), GetLastErrorMsg().c_str());
|
||||
ERROR_LOG(Log::Common, "CreateEmptyFile: failed to create '%s': %s", filename.c_str(), GetLastErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
fclose(pFile);
|
||||
@@ -903,11 +923,11 @@ bool DeleteDir(const Path &path) {
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(COMMON, "DeleteDir: directory %s", path.c_str());
|
||||
INFO_LOG(Log::Common, "DeleteDir: directory %s", path.c_str());
|
||||
|
||||
// check if a directory
|
||||
if (!File::IsDirectory(path)) {
|
||||
ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", path.c_str());
|
||||
ERROR_LOG(Log::Common, "DeleteDir: Not a directory %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -923,7 +943,7 @@ bool DeleteDir(const Path &path) {
|
||||
if (rmdir(path.c_str()) == 0)
|
||||
return true;
|
||||
#endif
|
||||
ERROR_LOG(COMMON, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str());
|
||||
ERROR_LOG(Log::Common, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -937,7 +957,7 @@ bool DeleteDirRecursively(const Path &path) {
|
||||
// We make use of the dangerous auto-recursive property of Android_RemoveFile.
|
||||
return Android_RemoveFile(path.ToString()) == StorageError::SUCCESS;
|
||||
default:
|
||||
ERROR_LOG(COMMON, "DeleteDirRecursively: Path type not supported");
|
||||
ERROR_LOG(Log::Common, "DeleteDirRecursively: Path type not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -958,7 +978,7 @@ bool OpenFileInEditor(const Path &fileName) {
|
||||
case PathType::NATIVE:
|
||||
break; // OK
|
||||
default:
|
||||
ERROR_LOG(COMMON, "OpenFileInEditor(%s): Path type not supported", fileName.c_str());
|
||||
ERROR_LOG(Log::Common, "OpenFileInEditor(%s): Path type not supported", fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -976,10 +996,10 @@ bool OpenFileInEditor(const Path &fileName) {
|
||||
iniFile = "xdg-open ";
|
||||
#endif
|
||||
iniFile.append(fileName.ToString());
|
||||
NOTICE_LOG(BOOT, "Launching %s", iniFile.c_str());
|
||||
NOTICE_LOG(Log::Boot, "Launching %s", iniFile.c_str());
|
||||
int retval = system(iniFile.c_str());
|
||||
if (retval != 0) {
|
||||
ERROR_LOG(COMMON, "Failed to launch ini file");
|
||||
ERROR_LOG(Log::Common, "Failed to launch ini file");
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
@@ -1115,7 +1135,7 @@ bool IOFile::Seek(int64_t off, int origin)
|
||||
}
|
||||
|
||||
uint64_t IOFile::Tell()
|
||||
{
|
||||
{
|
||||
if (IsOpen())
|
||||
return ftello(m_file);
|
||||
else
|
||||
@@ -1237,4 +1257,42 @@ bool WriteDataToFile(bool text_file, const void* data, size_t size, const Path &
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChangeMTime(const Path &path, time_t mtime) {
|
||||
if (path.Type() == PathType::CONTENT_URI) {
|
||||
// No clue what to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_utimbuf buf{};
|
||||
buf.actime = mtime;
|
||||
buf.modtime = mtime;
|
||||
_utime(path.c_str(), &buf);
|
||||
#else
|
||||
utimbuf buf{};
|
||||
buf.actime = mtime;
|
||||
buf.modtime = mtime;
|
||||
utime(path.c_str(), &buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsProbablyInDownloadsFolder(const Path &filename) {
|
||||
INFO_LOG(Log::Common, "IsProbablyInDownloadsFolder: Looking at %s (%s)...", filename.c_str(), filename.ToVisualString().c_str());
|
||||
switch (filename.Type()) {
|
||||
case PathType::CONTENT_URI:
|
||||
{
|
||||
AndroidContentURI uri(filename.ToString());
|
||||
INFO_LOG(Log::Common, "Content URI provider: %s", uri.Provider().c_str());
|
||||
if (containsNoCase(uri.Provider(), "download")) {
|
||||
// like com.android.providers.downloads.documents
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return filename.FilePathContainsNoCase("download");
|
||||
}
|
||||
|
||||
} // namespace File
|
||||
@@ -83,6 +83,8 @@ uint64_t ComputeRecursiveDirectorySize(const Path &path);
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const Path &filename);
|
||||
|
||||
void ChangeMTime(const Path &path, time_t mtime);
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const Path &fullPath);
|
||||
|
||||
@@ -120,6 +122,10 @@ bool CreateEmptyFile(const Path &filename);
|
||||
// TODO: Belongs in System or something.
|
||||
bool OpenFileInEditor(const Path &fileName);
|
||||
|
||||
// Uses some heuristics to determine if this is a folder that we would want to
|
||||
// write to.
|
||||
bool IsProbablyInDownloadsFolder(const Path &folder);
|
||||
|
||||
// TODO: Belongs in System or something.
|
||||
const Path &GetExeDirectory();
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void Path::Init(std::string_view str) {
|
||||
// and flip it to a NATIVE url and hope for the best.
|
||||
AndroidContentURI uri(str);
|
||||
if (startsWith(uri.FilePath(), "raw:/")) {
|
||||
INFO_LOG(SYSTEM, "Raw path detected: %s", uri.FilePath().c_str());
|
||||
INFO_LOG(Log::System, "Raw path detected: %s", uri.FilePath().c_str());
|
||||
path_ = uri.FilePath().substr(4);
|
||||
type_ = PathType::NATIVE;
|
||||
} else {
|
||||
@@ -240,6 +240,9 @@ bool Path::FilePathContainsNoCase(std::string_view needle) const {
|
||||
}
|
||||
|
||||
bool Path::StartsWith(const Path &other) const {
|
||||
if (other.empty()) {
|
||||
return true;
|
||||
}
|
||||
if (type_ != other.type_) {
|
||||
// Bad
|
||||
return false;
|
||||
|
||||
@@ -50,6 +50,9 @@ public:
|
||||
PathType Type() const {
|
||||
return type_;
|
||||
}
|
||||
bool IsLocalType() const {
|
||||
return type_ == PathType::NATIVE || type_ == PathType::CONTENT_URI;
|
||||
}
|
||||
|
||||
bool Valid() const { return !path_.empty(); }
|
||||
bool IsRoot() const { return path_ == "/"; } // Special value - only path that can end in a slash.
|
||||
|
||||
+41
-12
@@ -74,7 +74,7 @@ bool LoadRemoteFileList(const Path &url, const std::string &userAgent, bool *can
|
||||
// Try to extract from an automatic webserver directory listing...
|
||||
GetQuotedStrings(listing, items);
|
||||
} else {
|
||||
ERROR_LOG(IO, "Unsupported Content-Type: %s", contentType.c_str());
|
||||
ERROR_LOG(Log::IO, "Unsupported Content-Type: %s", contentType.c_str());
|
||||
return false;
|
||||
}
|
||||
Path basePath(baseURL.ToString());
|
||||
@@ -124,9 +124,15 @@ PathBrowser::~PathBrowser() {
|
||||
|
||||
void PathBrowser::SetPath(const Path &path) {
|
||||
path_ = path;
|
||||
ApplyRestriction();
|
||||
HandlePath();
|
||||
}
|
||||
|
||||
void PathBrowser::RestrictToRoot(const Path &root) {
|
||||
INFO_LOG(Log::System, "Restricting to root: %s", root.c_str());
|
||||
restrictedRoot_ = root;
|
||||
}
|
||||
|
||||
void PathBrowser::HandlePath() {
|
||||
if (!path_.empty() && path_.ToString()[0] == '!') {
|
||||
if (pendingActive_)
|
||||
@@ -162,24 +168,26 @@ void PathBrowser::HandlePath() {
|
||||
break;
|
||||
}
|
||||
lastPath = pendingPath_;
|
||||
bool success = false;
|
||||
if (lastPath.Type() == PathType::HTTP) {
|
||||
guard.unlock();
|
||||
results.clear();
|
||||
success = LoadRemoteFileList(lastPath, userAgent_, &pendingCancel_, results);
|
||||
success_ = LoadRemoteFileList(lastPath, userAgent_, &pendingCancel_, results);
|
||||
guard.lock();
|
||||
} else if (lastPath.empty()) {
|
||||
results.clear();
|
||||
success = true;
|
||||
success_ = true;
|
||||
} else {
|
||||
guard.unlock();
|
||||
results.clear();
|
||||
success = File::GetFilesInDir(lastPath, &results, nullptr);
|
||||
success_ = File::GetFilesInDir(lastPath, &results, nullptr);
|
||||
if (!success_) {
|
||||
WARN_LOG(Log::IO, "PathBrowser: Failed to list directory: %s", lastPath.c_str());
|
||||
}
|
||||
guard.lock();
|
||||
}
|
||||
|
||||
if (pendingPath_ == lastPath) {
|
||||
if (success && !pendingCancel_) {
|
||||
if (success_ && !pendingCancel_) {
|
||||
pendingFiles_ = results;
|
||||
}
|
||||
pendingPath_.clear();
|
||||
@@ -201,19 +209,28 @@ bool PathBrowser::IsListingReady() {
|
||||
}
|
||||
|
||||
std::string PathBrowser::GetFriendlyPath() const {
|
||||
std::string str = GetPath().ToVisualString();
|
||||
// Show relative to memstick root if there.
|
||||
if (startsWith(str, aliasMatch_)) {
|
||||
return aliasDisplay_ + str.substr(aliasMatch_.size());
|
||||
if (path_.StartsWith(aliasMatch_)) {
|
||||
std::string p;
|
||||
if (aliasMatch_.ComputePathTo(path_, p)) {
|
||||
return aliasDisplay_ + p;
|
||||
}
|
||||
std::string str = path_.ToString();
|
||||
if (aliasMatch_.size() < str.length()) {
|
||||
return aliasDisplay_ + str.substr(aliasMatch_.size());
|
||||
} else {
|
||||
return aliasDisplay_;
|
||||
}
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC)
|
||||
std::string str = path_.ToString();
|
||||
#if !PPSSPP_PLATFORM(ANDROID) && (PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC))
|
||||
char *home = getenv("HOME");
|
||||
if (home != nullptr && !strncmp(str.c_str(), home, strlen(home))) {
|
||||
str = std::string("~") + str.substr(strlen(home));
|
||||
return std::string("~") + str.substr(strlen(home));
|
||||
}
|
||||
#endif
|
||||
return str;
|
||||
return path_.ToVisualString();
|
||||
}
|
||||
|
||||
bool PathBrowser::GetListing(std::vector<File::FileInfo> &fileInfo, const char *filter, bool *cancel) {
|
||||
@@ -229,12 +246,24 @@ bool PathBrowser::GetListing(std::vector<File::FileInfo> &fileInfo, const char *
|
||||
return true;
|
||||
}
|
||||
|
||||
void PathBrowser::ApplyRestriction() {
|
||||
if (!path_.StartsWith(restrictedRoot_) && !startsWith(path_.ToString(), "!")) {
|
||||
WARN_LOG(Log::System, "Applying path restriction: %s (%s didn't match)", restrictedRoot_.c_str(), path_.c_str());
|
||||
path_ = restrictedRoot_;
|
||||
}
|
||||
}
|
||||
|
||||
bool PathBrowser::CanNavigateUp() {
|
||||
if (path_ == restrictedRoot_) {
|
||||
return false;
|
||||
}
|
||||
return path_.CanNavigateUp();
|
||||
}
|
||||
|
||||
void PathBrowser::NavigateUp() {
|
||||
_dbg_assert_(CanNavigateUp());
|
||||
path_ = path_.NavigateUp();
|
||||
ApplyRestriction();
|
||||
}
|
||||
|
||||
// TODO: Support paths like "../../hello"
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
#include "Common/File/DirListing.h"
|
||||
#include "Common/File/Path.h"
|
||||
|
||||
@@ -18,7 +17,6 @@
|
||||
class PathBrowser {
|
||||
public:
|
||||
PathBrowser() {}
|
||||
PathBrowser(const Path &path) { SetPath(path); }
|
||||
~PathBrowser();
|
||||
|
||||
void SetPath(const Path &path);
|
||||
@@ -41,24 +39,29 @@ public:
|
||||
void SetUserAgent(const std::string &s) {
|
||||
userAgent_ = s;
|
||||
}
|
||||
void SetRootAlias(const std::string &alias, const std::string &longValue) {
|
||||
void SetRootAlias(const std::string &alias, const Path &rootPath) {
|
||||
aliasDisplay_ = alias;
|
||||
aliasMatch_ = longValue;
|
||||
aliasMatch_ = rootPath;
|
||||
}
|
||||
|
||||
void RestrictToRoot(const Path &root);
|
||||
bool empty() const {
|
||||
return path_.empty();
|
||||
}
|
||||
bool Success() const {
|
||||
return success_;
|
||||
}
|
||||
|
||||
private:
|
||||
void HandlePath();
|
||||
void ResetPending();
|
||||
void ApplyRestriction();
|
||||
|
||||
Path path_;
|
||||
Path pendingPath_;
|
||||
Path restrictedRoot_;
|
||||
std::string userAgent_;
|
||||
std::string aliasDisplay_;
|
||||
std::string aliasMatch_;
|
||||
Path aliasMatch_;
|
||||
std::vector<File::FileInfo> pendingFiles_;
|
||||
std::condition_variable pendingCond_;
|
||||
std::mutex pendingLock_;
|
||||
@@ -67,5 +70,6 @@ private:
|
||||
bool pendingCancel_ = false;
|
||||
bool pendingStop_ = false;
|
||||
bool ready_ = false;
|
||||
bool success_ = true;
|
||||
};
|
||||
|
||||
+10
-10
@@ -11,9 +11,9 @@ VFS g_VFS;
|
||||
void VFS::Register(const char *prefix, VFSBackend *reader) {
|
||||
if (reader) {
|
||||
entries_.push_back(VFSEntry{ prefix, reader });
|
||||
DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
|
||||
DEBUG_LOG(Log::IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
|
||||
} else {
|
||||
ERROR_LOG(IO, "Trying to register null VFS backend for prefix %s", prefix);
|
||||
ERROR_LOG(Log::IO, "Trying to register null VFS backend for prefix %s", prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ void VFS::Clear() {
|
||||
}
|
||||
|
||||
// TODO: Use Path more.
|
||||
static bool IsLocalAbsolutePath(const char *path) {
|
||||
static bool IsLocalAbsolutePath(std::string_view path) {
|
||||
bool isUnixLocal = path[0] == '/';
|
||||
#ifdef _WIN32
|
||||
bool isWindowsLocal = (isalpha(path[0]) && path[1] == ':') || startsWith(path, "\\\\") || startsWith(path, "//");
|
||||
@@ -40,7 +40,7 @@ static bool IsLocalAbsolutePath(const char *path) {
|
||||
uint8_t *VFS::ReadFile(const char *filename, size_t *size) {
|
||||
if (IsLocalAbsolutePath(filename)) {
|
||||
// Local path, not VFS.
|
||||
// INFO_LOG(IO, "Not a VFS path: %s . Reading local file.", filename);
|
||||
// INFO_LOG(Log::IO, "Not a VFS path: %s . Reading local file.", filename);
|
||||
return File::ReadLocalFile(Path(filename), size);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ uint8_t *VFS::ReadFile(const char *filename, size_t *size) {
|
||||
if (prefix_len >= fn_len) continue;
|
||||
if (0 == memcmp(filename, entry.prefix, prefix_len)) {
|
||||
fileSystemFound = true;
|
||||
// INFO_LOG(IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
|
||||
// INFO_LOG(Log::IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
|
||||
uint8_t *data = entry.reader->ReadFile(filename + prefix_len, size);
|
||||
if (data)
|
||||
return data;
|
||||
@@ -61,7 +61,7 @@ uint8_t *VFS::ReadFile(const char *filename, size_t *size) {
|
||||
}
|
||||
}
|
||||
if (!fileSystemFound) {
|
||||
ERROR_LOG(IO, "Missing filesystem for '%s'", filename);
|
||||
ERROR_LOG(Log::IO, "Missing filesystem for '%s'", filename);
|
||||
} // Otherwise, the file was just missing. No need to log.
|
||||
return nullptr;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ uint8_t *VFS::ReadFile(const char *filename, size_t *size) {
|
||||
bool VFS::GetFileListing(const char *path, std::vector<File::FileInfo> *listing, const char *filter) {
|
||||
if (IsLocalAbsolutePath(path)) {
|
||||
// Local path, not VFS.
|
||||
// INFO_LOG(IO, "Not a VFS path: %s . Reading local directory.", path);
|
||||
// INFO_LOG(Log::IO, "Not a VFS path: %s . Reading local directory.", path);
|
||||
File::GetFilesInDir(Path(std::string(path)), listing, filter);
|
||||
return true;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ bool VFS::GetFileListing(const char *path, std::vector<File::FileInfo> *listing,
|
||||
}
|
||||
|
||||
if (!fileSystemFound) {
|
||||
ERROR_LOG(IO, "Missing filesystem for %s", path);
|
||||
ERROR_LOG(Log::IO, "Missing filesystem for %s", path);
|
||||
} // Otherwise, the file was just missing. No need to log.
|
||||
return false;
|
||||
}
|
||||
@@ -96,7 +96,7 @@ bool VFS::GetFileListing(const char *path, std::vector<File::FileInfo> *listing,
|
||||
bool VFS::GetFileInfo(const char *path, File::FileInfo *info) {
|
||||
if (IsLocalAbsolutePath(path)) {
|
||||
// Local path, not VFS.
|
||||
// INFO_LOG(IO, "Not a VFS path: %s . Getting local file info.", path);
|
||||
// INFO_LOG(Log::IO, "Not a VFS path: %s . Getting local file info.", path);
|
||||
return File::GetFileInfo(Path(std::string(path)), info);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ bool VFS::GetFileInfo(const char *path, File::FileInfo *info) {
|
||||
}
|
||||
}
|
||||
if (!fileSystemFound) {
|
||||
ERROR_LOG(IO, "Missing filesystem for '%s'", path);
|
||||
ERROR_LOG(Log::IO, "Missing filesystem for '%s'", path);
|
||||
} // Otherwise, the file was just missing. No need to log.
|
||||
return false;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath,
|
||||
int fd = File::OpenFD(zipFile, File::OPEN_READ);
|
||||
if (!fd) {
|
||||
if (logErrors) {
|
||||
ERROR_LOG(IO, "Failed to open FD for '%s' as zip file", zipFile.c_str());
|
||||
ERROR_LOG(Log::IO, "Failed to open FD for '%s' as zip file", zipFile.c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath,
|
||||
|
||||
if (!zip_file) {
|
||||
if (logErrors) {
|
||||
ERROR_LOG(IO, "Failed to open %s as a zip file", zipFile.c_str());
|
||||
ERROR_LOG(Log::IO, "Failed to open %s as a zip file", zipFile.c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ uint8_t *ZipFileReader::ReadFile(const char *path, size_t *size) {
|
||||
zip_stat(zip_file_, temp_path.c_str(), ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat);
|
||||
zip_file *file = zip_fopen(zip_file_, temp_path.c_str(), ZIP_FL_NOCASE | ZIP_FL_UNCHANGED);
|
||||
if (!file) {
|
||||
ERROR_LOG(IO, "Error opening %s from ZIP", temp_path.c_str());
|
||||
ERROR_LOG(Log::IO, "Error opening %s from ZIP", temp_path.c_str());
|
||||
return 0;
|
||||
}
|
||||
uint8_t *contents = new uint8_t[zstat.size + 1];
|
||||
@@ -107,7 +107,7 @@ bool ZipFileReader::GetFileListing(const char *orig_path, std::vector<File::File
|
||||
|
||||
listing->clear();
|
||||
|
||||
// INFO_LOG(SYSTEM, "Zip: Listing '%s'", orig_path);
|
||||
// INFO_LOG(Log::System, "Zip: Listing '%s'", orig_path);
|
||||
|
||||
listing->reserve(directories.size() + files.size());
|
||||
for (auto diter = directories.begin(); diter != directories.end(); ++diter) {
|
||||
@@ -120,7 +120,7 @@ bool ZipFileReader::GetFileListing(const char *orig_path, std::vector<File::File
|
||||
info.exists = true;
|
||||
info.isWritable = false;
|
||||
info.isDirectory = true;
|
||||
// INFO_LOG(SYSTEM, "Found file: %s (%s)", info.name.c_str(), info.fullName.c_str());
|
||||
// INFO_LOG(Log::System, "Found file: %s (%s)", info.name.c_str(), info.fullName.c_str());
|
||||
listing->push_back(info);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ bool ZipFileReader::GetFileListing(const char *orig_path, std::vector<File::File
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// INFO_LOG(SYSTEM, "Found dir: %s (%s)", info.name.c_str(), info.fullName.c_str());
|
||||
// INFO_LOG(Log::System, "Found dir: %s (%s)", info.name.c_str(), info.fullName.c_str());
|
||||
listing->push_back(info);
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ VFSOpenFile *ZipFileReader::OpenFileForRead(VFSFileReference *vfsReference, size
|
||||
|
||||
openFile->zf = zip_fopen_index(zip_file_, reference->zi, 0);
|
||||
if (!openFile->zf) {
|
||||
WARN_LOG(G3D, "File with index %d not found in zip", reference->zi);
|
||||
WARN_LOG(Log::G3D, "File with index %d not found in zip", reference->zi);
|
||||
lock_.unlock();
|
||||
delete openFile;
|
||||
return nullptr;
|
||||
|
||||
@@ -281,6 +281,8 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
|
||||
caps_.blendMinMaxSupported = true;
|
||||
caps_.multiSampleLevelsMask = 1; // More could be supported with some work.
|
||||
|
||||
caps_.provokingVertexLast = false; // D3D has it first, unfortunately. (and no way to change it).
|
||||
|
||||
caps_.presentInstantModeChange = true;
|
||||
caps_.presentMaxInterval = 4;
|
||||
caps_.presentModesSupported = PresentMode::FIFO | PresentMode::IMMEDIATE;
|
||||
@@ -1036,7 +1038,7 @@ void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **dat
|
||||
|
||||
ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) {
|
||||
if (language != ShaderLanguage::HLSL_D3D11) {
|
||||
ERROR_LOG(G3D, "Unsupported shader language");
|
||||
ERROR_LOG(Log::G3D, "Unsupported shader language");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1081,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang
|
||||
}
|
||||
if (errorMsgs) {
|
||||
errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize());
|
||||
ERROR_LOG(G3D, "Failed compiling %s:\n%s\n%s", tag, data, errors.c_str());
|
||||
ERROR_LOG(Log::G3D, "Failed compiling %s:\n%s\n%s", tag, data, errors.c_str());
|
||||
errorMsgs->Release();
|
||||
}
|
||||
|
||||
@@ -1104,7 +1106,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang
|
||||
result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs);
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(G3D, "Unsupported shader stage");
|
||||
ERROR_LOG(Log::G3D, "Unsupported shader stage");
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
@@ -1484,7 +1486,7 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) {
|
||||
depthViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
hr = device_->CreateShaderResourceView(fb->depthStencilTex, &depthViewDesc, &fb->depthSRView);
|
||||
if (FAILED(hr)) {
|
||||
WARN_LOG(G3D, "Failed to create SRV for depth buffer.");
|
||||
WARN_LOG(Log::G3D, "Failed to create SRV for depth buffer.");
|
||||
fb->depthSRView = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +375,7 @@ bool D3D9Texture::Create(const TextureDesc &desc) {
|
||||
break;
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
ERROR_LOG(G3D, "D3D9 Texture creation failed");
|
||||
ERROR_LOG(Log::G3D, "D3D9 Texture creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -486,7 +486,7 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d
|
||||
}
|
||||
|
||||
default:
|
||||
ERROR_LOG(G3D, "Non-LINEAR2D textures not yet supported");
|
||||
ERROR_LOG(Log::G3D, "Non-LINEAR2D textures not yet supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -733,7 +733,7 @@ static NVIDIAGeneration NVIDIAGetDeviceGeneration(int deviceID) {
|
||||
D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx)
|
||||
: d3d_(d3d), d3dEx_(d3dEx), device_(device), deviceEx_(deviceEx), adapterId_(adapterId), caps_{} {
|
||||
if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) {
|
||||
ERROR_LOG(G3D, "Failed to get adapter identifier: %d", adapterId);
|
||||
ERROR_LOG(Log::G3D, "Failed to get adapter identifier: %d", adapterId);
|
||||
}
|
||||
switch (identifier_.VendorId) {
|
||||
case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break;
|
||||
@@ -758,7 +758,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID
|
||||
if (SUCCEEDED(result)) {
|
||||
snprintf(shadeLangVersion_, sizeof(shadeLangVersion_), "PS: %04x VS: %04x", d3dCaps_.PixelShaderVersion & 0xFFFF, d3dCaps_.VertexShaderVersion & 0xFFFF);
|
||||
} else {
|
||||
WARN_LOG(G3D, "Direct3D9: Failed to get the device caps!");
|
||||
WARN_LOG(Log::G3D, "Direct3D9: Failed to get the device caps!");
|
||||
truncate_cpy(shadeLangVersion_, "N/A");
|
||||
}
|
||||
|
||||
@@ -786,6 +786,8 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID
|
||||
caps_.presentMaxInterval = 1;
|
||||
caps_.presentModesSupported = PresentMode::FIFO;
|
||||
|
||||
caps_.provokingVertexLast = false; // D3D has it first, unfortunately (and no way to change it).
|
||||
|
||||
if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) {
|
||||
caps_.anisoSupported = true;
|
||||
}
|
||||
@@ -846,13 +848,13 @@ ShaderModule *D3D9Context::CreateShaderModule(ShaderStage stage, ShaderLanguage
|
||||
|
||||
Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {
|
||||
if (!desc.shaders.size()) {
|
||||
ERROR_LOG(G3D, "Pipeline %s requires at least one shader", tag);
|
||||
ERROR_LOG(Log::G3D, "Pipeline %s requires at least one shader", tag);
|
||||
return NULL;
|
||||
}
|
||||
D3D9Pipeline *pipeline = new D3D9Pipeline();
|
||||
for (auto iter : desc.shaders) {
|
||||
if (!iter) {
|
||||
ERROR_LOG(G3D, "NULL shader passed to CreateGraphicsPipeline(%s)", tag);
|
||||
ERROR_LOG(Log::G3D, "NULL shader passed to CreateGraphicsPipeline(%s)", tag);
|
||||
delete pipeline;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1041,7 +1043,7 @@ D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc
|
||||
|
||||
HRESULT hr = device->CreateVertexDeclaration(elements, &decl_);
|
||||
if (FAILED(hr)) {
|
||||
ERROR_LOG(G3D, "Error creating vertex decl");
|
||||
ERROR_LOG(Log::G3D, "Error creating vertex decl");
|
||||
}
|
||||
delete[] elements;
|
||||
}
|
||||
@@ -1119,7 +1121,7 @@ void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offse
|
||||
if (!size)
|
||||
return;
|
||||
if (offset + size > buf->maxSize_) {
|
||||
ERROR_LOG(G3D, "Can't SubData with bigger size than buffer was created with");
|
||||
ERROR_LOG(Log::G3D, "Can't SubData with bigger size than buffer was created with");
|
||||
return;
|
||||
}
|
||||
if (buf->vbuffer_) {
|
||||
@@ -1253,8 +1255,8 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si
|
||||
error = "D3D9 shader compiler not installed";
|
||||
}
|
||||
|
||||
ERROR_LOG(G3D, "Compile error: %s", error);
|
||||
ERROR_LOG(G3D, "%s", LineNumberString(std::string((const char *)data)).c_str());
|
||||
ERROR_LOG(Log::G3D, "Compile error: %s", error);
|
||||
ERROR_LOG(Log::G3D, "%s", LineNumberString(std::string((const char *)data)).c_str());
|
||||
|
||||
OutputDebugStringA(source);
|
||||
OutputDebugStringA(error);
|
||||
@@ -1307,7 +1309,7 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) {
|
||||
|
||||
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");
|
||||
ERROR_LOG(Log::G3D, "Failed to create render target");
|
||||
fbo->Release();
|
||||
return NULL;
|
||||
}
|
||||
@@ -1323,7 +1325,7 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) {
|
||||
dsResult = device_->CreateDepthStencilSurface(desc.width, desc.height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &fbo->depthstencil, NULL);
|
||||
}
|
||||
if (FAILED(dsResult)) {
|
||||
ERROR_LOG(G3D, "Failed to create depth buffer");
|
||||
ERROR_LOG(Log::G3D, "Failed to create depth buffer");
|
||||
fbo->surf->Release();
|
||||
fbo->tex->Release();
|
||||
if (fbo->depthstenciltex) {
|
||||
@@ -1595,7 +1597,7 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi
|
||||
DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) {
|
||||
bool result = LoadD3DCompilerDynamic();
|
||||
if (!result) {
|
||||
ERROR_LOG(G3D, "Failed to load D3DCompiler!");
|
||||
ERROR_LOG(Log::G3D, "Failed to load D3DCompiler!");
|
||||
return nullptr;
|
||||
}
|
||||
return new D3D9Context(d3d, d3dEx, adapterId, device, deviceEx);
|
||||
|
||||
@@ -37,7 +37,7 @@ std::string GLEnumToString(uint16_t value) {
|
||||
bool CheckGLError(const char *file, int line) {
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
ERROR_LOG(G3D, "GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line);
|
||||
ERROR_LOG(Log::G3D, "GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -105,7 +105,7 @@ int GLExtensions::GLSLVersion() {
|
||||
void ProcessGPUFeatures() {
|
||||
gl_extensions.bugs = 0;
|
||||
|
||||
DEBUG_LOG(G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model);
|
||||
DEBUG_LOG(Log::G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model);
|
||||
|
||||
if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) {
|
||||
if (!strcmp(gl_extensions.model, "PowerVR SGX 545") ||
|
||||
@@ -115,11 +115,11 @@ void ProcessGPUFeatures() {
|
||||
!strcmp(gl_extensions.model, "PowerVR SGX 540") ||
|
||||
!strcmp(gl_extensions.model, "PowerVR SGX 530") ||
|
||||
!strcmp(gl_extensions.model, "PowerVR SGX 520") ) {
|
||||
WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad and terrible precision");
|
||||
WARN_LOG(Log::G3D, "GL DRIVER BUG: PVR with bad and terrible precision");
|
||||
gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_TERRIBLE | BUG_PVR_SHADER_PRECISION_BAD;
|
||||
} else {
|
||||
// TODO: I'm not sure if the Rogue series is affected by this.
|
||||
WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad precision");
|
||||
WARN_LOG(Log::G3D, "GL DRIVER BUG: PVR with bad precision");
|
||||
gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_BAD;
|
||||
}
|
||||
}
|
||||
@@ -193,14 +193,14 @@ bool CheckGLExtensions() {
|
||||
} else if (vendor == "Apple Inc." || vendor == "Apple") {
|
||||
gl_extensions.gpuVendor = GPU_VENDOR_APPLE;
|
||||
} else {
|
||||
WARN_LOG(G3D, "Unknown GL vendor: '%s'", vendor.c_str());
|
||||
WARN_LOG(Log::G3D, "Unknown GL vendor: '%s'", vendor.c_str());
|
||||
gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor ? cvendor : "N/A", renderer, versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A");
|
||||
INFO_LOG(Log::G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor ? cvendor : "N/A", renderer, versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A");
|
||||
|
||||
strncpy(gl_extensions.model, renderer, sizeof(gl_extensions.model));
|
||||
gl_extensions.model[sizeof(gl_extensions.model) - 1] = 0;
|
||||
@@ -263,7 +263,7 @@ bool CheckGLExtensions() {
|
||||
gl_extensions.ver[1] = 0;
|
||||
} else if (parsed[0] && (gl_extensions.ver[0] != parsed[0] || gl_extensions.ver[1] != parsed[1])) {
|
||||
// Something going wrong. Possible bug in GL ES drivers. See #9688
|
||||
INFO_LOG(G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.",
|
||||
INFO_LOG(Log::G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.",
|
||||
versionStr ? versionStr : "N/A", parsed[0], parsed[1], gl_extensions.ver[0], gl_extensions.ver[1]);
|
||||
|
||||
gl_extensions.ver[0] = 2;
|
||||
@@ -287,7 +287,7 @@ bool CheckGLExtensions() {
|
||||
gl_extensions.GLES3 = true;
|
||||
// Though, let's ban Mali from the GLES 3 path for now, see #4078
|
||||
if (strstr(renderer, "Mali") != 0) {
|
||||
INFO_LOG(G3D, "Forcing GLES3 off for Mali driver version: %s\n", versionStr ? versionStr : "N/A");
|
||||
INFO_LOG(Log::G3D, "Forcing GLES3 off for Mali driver version: %s\n", versionStr ? versionStr : "N/A");
|
||||
gl_extensions.GLES3 = false;
|
||||
}
|
||||
} else {
|
||||
@@ -308,9 +308,9 @@ bool CheckGLExtensions() {
|
||||
|
||||
if (gl_extensions.GLES3) {
|
||||
if (gl_extensions.ver[1] >= 1) {
|
||||
INFO_LOG(G3D, "OpenGL ES 3.1 support detected!\n");
|
||||
INFO_LOG(Log::G3D, "OpenGL ES 3.1 support detected!\n");
|
||||
} else {
|
||||
INFO_LOG(G3D, "OpenGL ES 3.0 support detected!\n");
|
||||
INFO_LOG(Log::G3D, "OpenGL ES 3.0 support detected!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,7 +404,7 @@ bool CheckGLExtensions() {
|
||||
#ifdef _DEBUG
|
||||
void *invalidAddress = (void *)eglGetProcAddress("InvalidGlCall1");
|
||||
void *invalidAddress2 = (void *)eglGetProcAddress("AnotherInvalidGlCall2");
|
||||
DEBUG_LOG(G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2);
|
||||
DEBUG_LOG(Log::G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2);
|
||||
#endif
|
||||
|
||||
// These are all the same. Let's alias.
|
||||
@@ -505,7 +505,7 @@ bool CheckGLExtensions() {
|
||||
// The model number comparison should probably be 400 or 500. This causes us to avoid depal-in-shader.
|
||||
// It seems though that this caused large perf regressions on Adreno 5xx, so I've bumped it up to 600.
|
||||
if (gl_extensions.gpuVendor == GPU_VENDOR_QUALCOMM && gl_extensions.modelNumber < 600) {
|
||||
WARN_LOG(G3D, "Detected old Adreno - lowering reported int precision for safety");
|
||||
WARN_LOG(Log::G3D, "Detected old Adreno - lowering reported int precision for safety");
|
||||
gl_extensions.range[1][5][0] = 15;
|
||||
gl_extensions.range[1][5][1] = 15;
|
||||
}
|
||||
@@ -615,7 +615,7 @@ bool CheckGLExtensions() {
|
||||
|
||||
int error = glGetError();
|
||||
if (error)
|
||||
ERROR_LOG(G3D, "GL error in init: %i", error);
|
||||
ERROR_LOG(Log::G3D, "GL error in init: %i", error);
|
||||
|
||||
#endif
|
||||
return true;
|
||||
|
||||
@@ -137,7 +137,7 @@ void GLPushBuffer::Flush() {
|
||||
}
|
||||
|
||||
void GLPushBuffer::AddBuffer() {
|
||||
// INFO_LOG(G3D, "GLPushBuffer(%s): Allocating %d bytes", tag_, size_);
|
||||
// INFO_LOG(Log::G3D, "GLPushBuffer(%s): Allocating %d bytes", tag_, size_);
|
||||
BufInfo info;
|
||||
info.localMemory = (uint8_t *)AllocateAlignedMemory(size_, 16);
|
||||
_assert_msg_(info.localMemory != 0, "GLPushBuffer alloc fail: %d (%s)", (int)size_, tag_);
|
||||
|
||||
@@ -107,19 +107,6 @@ static std::string GetInfoLog(GLuint name, Getiv getiv, GetLog getLog) {
|
||||
return infoLog;
|
||||
}
|
||||
|
||||
static int GetStereoBufferIndex(const char *uniformName) {
|
||||
if (!uniformName) return -1;
|
||||
else if (strcmp(uniformName, "u_view") == 0) return 0;
|
||||
else if (strcmp(uniformName, "u_proj_lens") == 0) return 1;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
static std::string GetStereoBufferLayout(const char *uniformName) {
|
||||
if (strcmp(uniformName, "u_view") == 0) return "ViewMatrices";
|
||||
else if (strcmp(uniformName, "u_proj_lens") == 0) return "ProjectionMatrix";
|
||||
else return "undefined";
|
||||
}
|
||||
|
||||
void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLCalls) {
|
||||
if (skipGLCalls) {
|
||||
// Some bookkeeping still needs to be done.
|
||||
@@ -143,12 +130,12 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
|
||||
}
|
||||
case GLRInitStepType::CREATE_PROGRAM:
|
||||
{
|
||||
WARN_LOG(G3D, "CREATE_PROGRAM found with skipGLCalls, not good");
|
||||
WARN_LOG(Log::G3D, "CREATE_PROGRAM found with skipGLCalls, not good");
|
||||
break;
|
||||
}
|
||||
case GLRInitStepType::CREATE_SHADER:
|
||||
{
|
||||
WARN_LOG(G3D, "CREATE_SHADER found with skipGLCalls, not good");
|
||||
WARN_LOG(Log::G3D, "CREATE_SHADER found with skipGLCalls, not good");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -250,11 +237,11 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
|
||||
if (!anyFailed)
|
||||
Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", infoLog.c_str(), fsDesc.c_str(), fsCode, vsDesc.c_str(), vsCode);
|
||||
|
||||
ERROR_LOG(G3D, "Could not link program:\n %s", infoLog.c_str());
|
||||
ERROR_LOG(G3D, "VS desc:\n%s", vsDesc.c_str());
|
||||
ERROR_LOG(G3D, "FS desc:\n%s", fsDesc.c_str());
|
||||
ERROR_LOG(G3D, "VS:\n%s\n", LineNumberString(vsCode).c_str());
|
||||
ERROR_LOG(G3D, "FS:\n%s\n", LineNumberString(fsCode).c_str());
|
||||
ERROR_LOG(Log::G3D, "Could not link program:\n %s", infoLog.c_str());
|
||||
ERROR_LOG(Log::G3D, "VS desc:\n%s", vsDesc.c_str());
|
||||
ERROR_LOG(Log::G3D, "FS desc:\n%s", fsDesc.c_str());
|
||||
ERROR_LOG(Log::G3D, "VS:\n%s\n", LineNumberString(vsCode).c_str());
|
||||
ERROR_LOG(Log::G3D, "FS:\n%s\n", LineNumberString(fsCode).c_str());
|
||||
|
||||
#ifdef _WIN32
|
||||
OutputDebugStringUTF8(infoLog.c_str());
|
||||
@@ -274,28 +261,10 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
|
||||
auto &query = program->queries_[j];
|
||||
_dbg_assert_(query.name);
|
||||
|
||||
int location = -1;
|
||||
if (IsVREnabled() && IsMultiviewSupported()) {
|
||||
int index = GetStereoBufferIndex(query.name);
|
||||
if (index >= 0) {
|
||||
std::string layout = GetStereoBufferLayout(query.name);
|
||||
glUniformBlockBinding(program->program, glGetUniformBlockIndex(program->program, layout.c_str()), index);
|
||||
|
||||
GLuint buffer = 0;
|
||||
glGenBuffers(1, &buffer);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER,2 * 16 * sizeof(float),NULL, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
location = buffer;
|
||||
} else {
|
||||
location = glGetUniformLocation(program->program, query.name);
|
||||
}
|
||||
} else {
|
||||
location = glGetUniformLocation(program->program, query.name);
|
||||
}
|
||||
int location = glGetUniformLocation(program->program, query.name);
|
||||
|
||||
if (location < 0 && query.required) {
|
||||
WARN_LOG(G3D, "Required uniform query for '%s' failed", query.name);
|
||||
WARN_LOG(Log::G3D, "Required uniform query for '%s' failed", query.name);
|
||||
}
|
||||
*query.dest = location;
|
||||
}
|
||||
@@ -337,7 +306,7 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
|
||||
std::vector<std::string_view> lines;
|
||||
SplitString(errorString, '\n', lines);
|
||||
for (auto line : lines) {
|
||||
ERROR_LOG(G3D, "%.*s", (int)line.size(), line.data());
|
||||
ERROR_LOG(Log::G3D, "%.*s", (int)line.size(), line.data());
|
||||
}
|
||||
if (errorCallback_) {
|
||||
std::string desc = StringFromFormat("Shader compilation failed: %s", step.create_shader.stage == GL_VERTEX_SHADER ? "vertex" : "fragment");
|
||||
@@ -462,12 +431,12 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
|
||||
// Calling glGetError() isn't great, but at the end of init, only after creating textures, shouldn't be too bad...
|
||||
GLenum err = glGetError();
|
||||
if (err == GL_OUT_OF_MEMORY) {
|
||||
WARN_LOG_REPORT(G3D, "GL ran out of GPU memory; switching to low memory mode");
|
||||
WARN_LOG_REPORT(Log::G3D, "GL ran out of GPU memory; switching to low memory mode");
|
||||
sawOutOfMemory_ = true;
|
||||
} else if (err != GL_NO_ERROR) {
|
||||
// We checked the err anyway, might as well log if there is one.
|
||||
std::string errorString = GLEnumToString(err);
|
||||
WARN_LOG(G3D, "Got an error after init: %08x (%s)", err, errorString.c_str());
|
||||
WARN_LOG(Log::G3D, "Got an error after init: %08x (%s)", err, errorString.c_str());
|
||||
if (errorCallback_) {
|
||||
errorCallback_("GL frame init error", errorString.c_str(), errorCallbackUserData_);
|
||||
}
|
||||
@@ -525,7 +494,7 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) {
|
||||
|
||||
retry_depth:
|
||||
if (!fbo->z_stencil_) {
|
||||
INFO_LOG(G3D, "Creating %d x %d FBO using no depth", fbo->width, fbo->height);
|
||||
INFO_LOG(Log::G3D, "Creating %d x %d FBO using no depth", fbo->width, fbo->height);
|
||||
|
||||
fbo->z_stencil_buffer = 0;
|
||||
fbo->stencil_buffer = 0;
|
||||
@@ -538,7 +507,7 @@ retry_depth:
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
} else if (gl_extensions.IsGLES) {
|
||||
if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) {
|
||||
INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height);
|
||||
INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height);
|
||||
fbo->z_stencil_buffer = 0;
|
||||
fbo->stencil_buffer = 0;
|
||||
fbo->z_buffer = 0;
|
||||
@@ -559,7 +528,7 @@ retry_depth:
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0);
|
||||
}
|
||||
} else if (gl_extensions.OES_packed_depth_stencil) {
|
||||
INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8", fbo->width, fbo->height);
|
||||
INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8", fbo->width, fbo->height);
|
||||
// Standard method
|
||||
fbo->stencil_buffer = 0;
|
||||
fbo->z_buffer = 0;
|
||||
@@ -574,7 +543,7 @@ retry_depth:
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
||||
} else {
|
||||
INFO_LOG(G3D, "Creating %d x %d FBO using separate stencil", fbo->width, fbo->height);
|
||||
INFO_LOG(Log::G3D, "Creating %d x %d FBO using separate stencil", fbo->width, fbo->height);
|
||||
// TEGRA
|
||||
fbo->z_stencil_buffer = 0;
|
||||
// 16/24-bit Z, separate 8-bit stencil
|
||||
@@ -595,7 +564,7 @@ retry_depth:
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer);
|
||||
}
|
||||
} else if (gl_extensions.VersionGEThan(3, 0)) {
|
||||
INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height);
|
||||
INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height);
|
||||
fbo->z_stencil_buffer = 0;
|
||||
fbo->stencil_buffer = 0;
|
||||
fbo->z_buffer = 0;
|
||||
@@ -631,13 +600,13 @@ retry_depth:
|
||||
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
// INFO_LOG(G3D, "Framebuffer verified complete.");
|
||||
// INFO_LOG(Log::G3D, "Framebuffer verified complete.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
ERROR_LOG(G3D, "GL_FRAMEBUFFER_UNSUPPORTED");
|
||||
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_UNSUPPORTED");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
ERROR_LOG(G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
|
||||
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(false, "Other framebuffer error: %d", status);
|
||||
@@ -778,7 +747,7 @@ void GLQueueRunner::PerformBlit(const GLRStep &step) {
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
#endif // defined(USING_GLES2) && defined(__ANDROID__)
|
||||
} else {
|
||||
ERROR_LOG(G3D, "GLQueueRunner: Tried to blit without the capability");
|
||||
ERROR_LOG(Log::G3D, "GLQueueRunner: Tried to blit without the capability");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1119,36 +1088,22 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
||||
case GLRRenderCommand::UNIFORMSTEREOMATRIX:
|
||||
{
|
||||
_dbg_assert_(curProgram);
|
||||
if (IsMultiviewSupported()) {
|
||||
int layout = GetStereoBufferIndex(c.uniformStereoMatrix4.name);
|
||||
if (layout >= 0) {
|
||||
int size = 2 * 16 * sizeof(float);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, layout, *c.uniformStereoMatrix4.loc);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, *c.uniformStereoMatrix4.loc);
|
||||
void *matrices = glMapBufferRange(GL_UNIFORM_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
memcpy(matrices, c.uniformStereoMatrix4.mData, size);
|
||||
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
delete[] c.uniformStereoMatrix4.mData; // We only playback once.
|
||||
} else {
|
||||
int loc = c.uniformStereoMatrix4.loc ? *c.uniformStereoMatrix4.loc : -1;
|
||||
if (c.uniformStereoMatrix4.name) {
|
||||
loc = curProgram->GetUniformLoc(c.uniformStereoMatrix4.name);
|
||||
}
|
||||
if (loc >= 0) {
|
||||
if (GetVRFBOIndex() == 0) {
|
||||
glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData);
|
||||
} else {
|
||||
glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData + 16);
|
||||
}
|
||||
}
|
||||
if (GetVRFBOIndex() == 1 || GetVRPassesCount() == 1) {
|
||||
// Only delete the data if we're rendering the only or the second eye.
|
||||
// If we delete during the first eye, we get a use-after-free or double delete.
|
||||
delete[] c.uniformStereoMatrix4.mData;
|
||||
int loc = c.uniformStereoMatrix4.loc ? *c.uniformStereoMatrix4.loc : -1;
|
||||
if (c.uniformStereoMatrix4.name) {
|
||||
loc = curProgram->GetUniformLoc(c.uniformStereoMatrix4.name);
|
||||
}
|
||||
if (loc >= 0) {
|
||||
if (GetVRFBOIndex() == 0) {
|
||||
glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData);
|
||||
} else {
|
||||
glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData + 16);
|
||||
}
|
||||
}
|
||||
if (GetVRFBOIndex() == 1 || GetVRPassesCount() == 1) {
|
||||
// Only delete the data if we're rendering the only or the second eye.
|
||||
// If we delete during the first eye, we get a use-after-free or double delete.
|
||||
delete[] c.uniformStereoMatrix4.mData;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
break;
|
||||
}
|
||||
@@ -1739,13 +1694,13 @@ void GLQueueRunner::fbo_ext_create(const GLRInitStep &step) {
|
||||
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
// INFO_LOG(G3D, "Framebuffer verified complete.");
|
||||
// INFO_LOG(Log::G3D, "Framebuffer verified complete.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
ERROR_LOG(G3D, "GL_FRAMEBUFFER_UNSUPPORTED");
|
||||
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_UNSUPPORTED");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
||||
ERROR_LOG(G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
|
||||
ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(false, "Other framebuffer error: %d", status);
|
||||
|
||||
@@ -298,7 +298,7 @@ enum GLRAspect {
|
||||
const char *GLRAspectToString(GLRAspect aspect);
|
||||
|
||||
struct GLRStep {
|
||||
GLRStep(GLRStepType _type) : stepType(_type) {}
|
||||
GLRStep(GLRStepType _type) : stepType(_type), tag() {}
|
||||
GLRStepType stepType;
|
||||
FastVec<GLRRenderData> commands;
|
||||
TinySet<const GLRFramebuffer *, 8> dependencies;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "Common/Math/math_util.h"
|
||||
|
||||
#if 0 // def _DEBUG
|
||||
#define VLOG(...) INFO_LOG(G3D, __VA_ARGS__)
|
||||
#define VLOG(...) INFO_LOG(Log::G3D, __VA_ARGS__)
|
||||
#else
|
||||
#define VLOG(...)
|
||||
#endif
|
||||
@@ -59,7 +59,7 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) {
|
||||
renderThreadId = std::this_thread::get_id();
|
||||
|
||||
if (newInflightFrames_ != -1) {
|
||||
INFO_LOG(G3D, "Updating inflight frames to %d", newInflightFrames_);
|
||||
INFO_LOG(Log::G3D, "Updating inflight frames to %d", newInflightFrames_);
|
||||
inflightFrames_ = newInflightFrames_;
|
||||
newInflightFrames_ = -1;
|
||||
}
|
||||
@@ -99,7 +99,7 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) {
|
||||
}
|
||||
|
||||
void GLRenderManager::ThreadEnd() {
|
||||
INFO_LOG(G3D, "ThreadEnd");
|
||||
INFO_LOG(Log::G3D, "ThreadEnd");
|
||||
|
||||
queueRunner_.DestroyDeviceObjects();
|
||||
VLOG(" PULL: Quitting");
|
||||
@@ -171,7 +171,7 @@ bool GLRenderManager::ThreadFrame() {
|
||||
|
||||
void GLRenderManager::StopThread() {
|
||||
// There's not really a lot to do here anymore.
|
||||
INFO_LOG(G3D, "GLRenderManager::StopThread()");
|
||||
INFO_LOG(Log::G3D, "GLRenderManager::StopThread()");
|
||||
if (runCompileThread_) {
|
||||
runCompileThread_ = false;
|
||||
|
||||
@@ -179,7 +179,17 @@ void GLRenderManager::StopThread() {
|
||||
renderThreadQueue_.push(new GLRRenderThreadTask(GLRRunType::EXIT));
|
||||
pushCondVar_.notify_one();
|
||||
} else {
|
||||
WARN_LOG(G3D, "GL submission thread was already paused.");
|
||||
WARN_LOG(Log::G3D, "GL submission thread was already paused.");
|
||||
}
|
||||
}
|
||||
|
||||
void GLRenderManager::StartThread() {
|
||||
// There's not really a lot to do here anymore.
|
||||
INFO_LOG(Log::G3D, "GLRenderManager::StartThread()");
|
||||
if (!runCompileThread_) {
|
||||
runCompileThread_ = true;
|
||||
} else {
|
||||
INFO_LOG(Log::G3D, "GL submission thread was already running.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +358,9 @@ void GLRenderManager::BeginFrame(bool enableProfiling) {
|
||||
curProgram_ = nullptr;
|
||||
#endif
|
||||
|
||||
// Shouldn't call BeginFrame unless we're in a run state.
|
||||
_dbg_assert_(runCompileThread_);
|
||||
|
||||
int curFrame = GetCurFrame();
|
||||
|
||||
FrameTimeData &frameTimeData = frameTimeHistory_.Add(frameIdGen_);
|
||||
@@ -368,10 +381,6 @@ void GLRenderManager::BeginFrame(bool enableProfiling) {
|
||||
frameData.readyForFence = false;
|
||||
}
|
||||
|
||||
if (!runCompileThread_) {
|
||||
WARN_LOG(G3D, "BeginFrame while !run_!");
|
||||
}
|
||||
|
||||
insideFrame_ = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -421,7 +421,6 @@ public:
|
||||
// an init command, that's for sure.
|
||||
GLRInitStep &step = initSteps_.push_uninitialized();
|
||||
step.stepType = GLRInitStepType::BUFFER_SUBDATA;
|
||||
_dbg_assert_(offset >= 0);
|
||||
_dbg_assert_(offset <= buffer->size_ - size);
|
||||
step.buffer_subdata.buffer = buffer;
|
||||
step.buffer_subdata.offset = (int)offset;
|
||||
@@ -835,6 +834,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void StartThread(); // Currently only used on iOS, since we fully recreate the context on Android
|
||||
void StopThread();
|
||||
|
||||
bool SawOutOfMemory() {
|
||||
@@ -874,6 +874,7 @@ private:
|
||||
FastVec<GLRInitStep> initSteps_;
|
||||
|
||||
// Execution time state
|
||||
// TODO: Rename this, as we don't actually use a compile thread on OpenGL.
|
||||
bool runCompileThread_ = true;
|
||||
|
||||
// Thread is managed elsewhere, and should call ThreadFrame.
|
||||
|
||||
@@ -23,9 +23,9 @@ bool CompileShader(const char *source, GLuint shader, const char *filename, std:
|
||||
GLsizei len;
|
||||
glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
|
||||
infoLog[len] = '\0';
|
||||
ERROR_LOG(G3D, "Error in shader compilation of %s!\n", filename);
|
||||
ERROR_LOG(G3D, "Info log: %s\n", infoLog);
|
||||
ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)source);
|
||||
ERROR_LOG(Log::G3D, "Error in shader compilation of %s!\n", filename);
|
||||
ERROR_LOG(Log::G3D, "Info log: %s\n", infoLog);
|
||||
ERROR_LOG(Log::G3D, "Shader source:\n%s\n", (const char *)source);
|
||||
if (error_message)
|
||||
*error_message = infoLog;
|
||||
return false;
|
||||
@@ -46,7 +46,7 @@ GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src
|
||||
if (glsl_recompile(program, error_message)) {
|
||||
active_programs.insert(program);
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed compiling GLSL program from source strings");
|
||||
ERROR_LOG(Log::G3D, "Failed compiling GLSL program from source strings");
|
||||
delete program;
|
||||
return 0;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
|
||||
vsh_src.reset((char *)g_VFS.ReadFile(program->vshader_filename, &sz));
|
||||
}
|
||||
if (!program->vshader_source && !vsh_src) {
|
||||
ERROR_LOG(G3D, "File missing: %s", program->vshader_filename);
|
||||
ERROR_LOG(Log::G3D, "File missing: %s", program->vshader_filename);
|
||||
if (error_message) {
|
||||
*error_message = std::string("File missing: ") + program->vshader_filename;
|
||||
}
|
||||
@@ -116,7 +116,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
|
||||
fsh_src.reset((char *)g_VFS.ReadFile(program->fshader_filename, &sz));
|
||||
}
|
||||
if (!program->fshader_source && !fsh_src) {
|
||||
ERROR_LOG(G3D, "File missing: %s", program->fshader_filename);
|
||||
ERROR_LOG(Log::G3D, "File missing: %s", program->fshader_filename);
|
||||
if (error_message) {
|
||||
*error_message = std::string("File missing: ") + program->fshader_filename;
|
||||
}
|
||||
@@ -150,15 +150,15 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
|
||||
if (bufLength) {
|
||||
char* buf = new char[bufLength + 1]; // safety
|
||||
glGetProgramInfoLog(prog, bufLength, NULL, buf);
|
||||
INFO_LOG(G3D, "vsh: %i fsh: %i", vsh, fsh);
|
||||
ERROR_LOG(G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf);
|
||||
INFO_LOG(Log::G3D, "vsh: %i fsh: %i", vsh, fsh);
|
||||
ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf);
|
||||
if (error_message) {
|
||||
*error_message = buf;
|
||||
}
|
||||
delete [] buf;
|
||||
} else {
|
||||
INFO_LOG(G3D, "vsh: %i fsh: %i", vsh, fsh);
|
||||
ERROR_LOG(G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus);
|
||||
INFO_LOG(Log::G3D, "vsh: %i fsh: %i", vsh, fsh);
|
||||
ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus);
|
||||
if (error_message) {
|
||||
*error_message = "(no error message available)";
|
||||
}
|
||||
@@ -193,7 +193,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
|
||||
program->u_sundir = glGetUniformLocation(program->program_, "u_sundir");
|
||||
program->u_camerapos = glGetUniformLocation(program->program_, "u_camerapos");
|
||||
|
||||
//INFO_LOG(G3D, "Shader compilation success: %s %s",
|
||||
//INFO_LOG(Log::G3D, "Shader compilation success: %s %s",
|
||||
// program->vshader_filename,
|
||||
// program->fshader_filename);
|
||||
return true;
|
||||
@@ -214,7 +214,7 @@ void glsl_destroy(GLSLProgram *program) {
|
||||
glDeleteProgram(program->program_);
|
||||
active_programs.erase(program);
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Deleting null GLSL program!");
|
||||
ERROR_LOG(Log::G3D, "Deleting null GLSL program!");
|
||||
}
|
||||
delete program;
|
||||
}
|
||||
|
||||
@@ -598,6 +598,9 @@ OpenGLContext::OpenGLContext(bool canChangeSwapInterval) : renderManager_(frameT
|
||||
// GLES has no support for logic framebuffer operations. There doesn't even seem to exist any such extensions.
|
||||
caps_.logicOpSupported = !gl_extensions.IsGLES;
|
||||
|
||||
// Always the case in GL (which is what we want for PSP flat shade).
|
||||
caps_.provokingVertexLast = true;
|
||||
|
||||
// Interesting potential hack for emulating GL_DEPTH_CLAMP (use a separate varying, force depth in fragment shader):
|
||||
// This will induce a performance penalty on many architectures though so a blanket enable of this
|
||||
// is probably not a good idea.
|
||||
@@ -843,7 +846,7 @@ static GLuint TypeToTarget(TextureType type) {
|
||||
#endif
|
||||
case TextureType::ARRAY2D: return GL_TEXTURE_2D_ARRAY;
|
||||
default:
|
||||
ERROR_LOG(G3D, "Bad texture type %d", (int)type);
|
||||
ERROR_LOG(Log::G3D, "Bad texture type %d", (int)type);
|
||||
return GL_NONE;
|
||||
}
|
||||
}
|
||||
@@ -998,30 +1001,30 @@ static void LogReadPixelsError(GLenum error) {
|
||||
case GL_NO_ERROR:
|
||||
break;
|
||||
case GL_INVALID_ENUM:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_INVALID_ENUM");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_ENUM");
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_INVALID_VALUE");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_VALUE");
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_INVALID_OPERATION");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_OPERATION");
|
||||
break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION");
|
||||
break;
|
||||
case GL_OUT_OF_MEMORY:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_OUT_OF_MEMORY");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_OUT_OF_MEMORY");
|
||||
break;
|
||||
#ifndef USING_GLES2
|
||||
case GL_STACK_UNDERFLOW:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_STACK_UNDERFLOW");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_STACK_UNDERFLOW");
|
||||
break;
|
||||
case GL_STACK_OVERFLOW:
|
||||
ERROR_LOG(G3D, "glReadPixels: GL_STACK_OVERFLOW");
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: GL_STACK_OVERFLOW");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ERROR_LOG(G3D, "glReadPixels: %08x", error);
|
||||
ERROR_LOG(Log::G3D, "glReadPixels: %08x", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1166,15 +1169,15 @@ void OpenGLContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t off
|
||||
|
||||
Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {
|
||||
if (!desc.shaders.size()) {
|
||||
ERROR_LOG(G3D, "Pipeline requires at least one shader");
|
||||
ERROR_LOG(Log::G3D, "Pipeline requires at least one shader");
|
||||
return nullptr;
|
||||
}
|
||||
if ((uint32_t)desc.prim >= (uint32_t)Primitive::PRIMITIVE_TYPE_COUNT) {
|
||||
ERROR_LOG(G3D, "Invalid primitive type");
|
||||
ERROR_LOG(Log::G3D, "Invalid primitive type");
|
||||
return nullptr;
|
||||
}
|
||||
if (!desc.depthStencil || !desc.blend || !desc.raster) {
|
||||
ERROR_LOG(G3D, "Incomplete prim desciption");
|
||||
ERROR_LOG(Log::G3D, "Incomplete prim desciption");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1184,7 +1187,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const
|
||||
iter->AddRef();
|
||||
pipeline->shaders.push_back(static_cast<OpenGLShaderModule *>(iter));
|
||||
} else {
|
||||
ERROR_LOG(G3D, "ERROR: Tried to create graphics pipeline %s with a null shader module", tag ? tag : "no tag");
|
||||
ERROR_LOG(Log::G3D, "ERROR: Tried to create graphics pipeline %s with a null shader module", tag ? tag : "no tag");
|
||||
delete pipeline;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1205,7 +1208,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const
|
||||
pipeline->inputLayout = (OpenGLInputLayout *)desc.inputLayout;
|
||||
return pipeline;
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed to create pipeline %s - shaders failed to link", tag ? tag : "no tag");
|
||||
ERROR_LOG(Log::G3D, "Failed to create pipeline %s - shaders failed to link", tag ? tag : "no tag");
|
||||
delete pipeline;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1274,11 +1277,11 @@ bool OpenGLPipeline::LinkShaders(const PipelineDesc &desc) {
|
||||
if (shader) {
|
||||
linkShaders.push_back(shader);
|
||||
} else {
|
||||
ERROR_LOG(G3D, "LinkShaders: Bad shader module");
|
||||
ERROR_LOG(Log::G3D, "LinkShaders: Bad shader module");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ERROR_LOG(G3D, "LinkShaders: Bad shader in module");
|
||||
ERROR_LOG(Log::G3D, "LinkShaders: Bad shader in module");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1462,7 +1465,7 @@ void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) {
|
||||
break;
|
||||
case DataFormat::UNDEFINED:
|
||||
default:
|
||||
ERROR_LOG(G3D, "Thin3DGLVertexFormat: Invalid or unknown component type applied.");
|
||||
ERROR_LOG(Log::G3D, "Thin3DGLVertexFormat: Invalid or unknown component type applied.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada
|
||||
}
|
||||
|
||||
// DUMPLOG(src.c_str());
|
||||
// INFO_LOG(SYSTEM, "---->");
|
||||
// INFO_LOG(Log::System, "---->");
|
||||
// DUMPLOG(LineNumberString(out.str()).c_str());
|
||||
|
||||
*dest = out.str();
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "VulkanLoader.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "VulkanBarrier.h"
|
||||
#include "VulkanFramebuffer.h"
|
||||
|
||||
#include "Common/Log.h"
|
||||
|
||||
VulkanBarrierBatch::~VulkanBarrierBatch() {
|
||||
// _dbg_assert_(imageBarriers_.empty());
|
||||
if (!imageBarriers_.empty()) {
|
||||
ERROR_LOG(G3D, "~VulkanBarrierBatch: %d barriers remaining", (int)imageBarriers_.size());
|
||||
ERROR_LOG(Log::G3D, "~VulkanBarrierBatch: %d barriers remaining", (int)imageBarriers_.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,30 +51,29 @@ void VulkanBarrierBatch::TransitionImage(
|
||||
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
}
|
||||
|
||||
void VulkanBarrierBatch::TransitionImageAuto(
|
||||
VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout) {
|
||||
void VulkanBarrierBatch::TransitionColorImageAuto(
|
||||
VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers) {
|
||||
_dbg_assert_(image != VK_NULL_HANDLE);
|
||||
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
VkAccessFlags dstAccessMask = 0;
|
||||
switch (oldImageLayout) {
|
||||
switch (*imageLayout) {
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
srcAccessMask = 0;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
// Assert aspect here?
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
// Assert aspect here?
|
||||
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
// We came from the Mali workaround, and are transitioning back to COLOR_ATTACHMENT_OPTIMAL.
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
// Actually this seems wrong?
|
||||
if (aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
}
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
// We only texture from images in the fragment shader, so can do this simply.
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
@@ -84,7 +84,7 @@ void VulkanBarrierBatch::TransitionImageAuto(
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(false, "Unexpected oldLayout: %d", (int)oldImageLayout);
|
||||
_assert_msg_(false, "Unexpected oldLayout: %s", VulkanImageLayoutToString(*imageLayout));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -93,8 +93,20 @@ void VulkanBarrierBatch::TransitionImageAuto(
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(false, "Unexpected newLayout: %d", (int)newImageLayout);
|
||||
_assert_msg_(false, "Unexpected newLayout: %s", VulkanImageLayoutToString(newImageLayout));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -103,33 +115,98 @@ void VulkanBarrierBatch::TransitionImageAuto(
|
||||
imageBarrier.pNext = nullptr;
|
||||
imageBarrier.srcAccessMask = srcAccessMask;
|
||||
imageBarrier.dstAccessMask = dstAccessMask;
|
||||
imageBarrier.oldLayout = oldImageLayout;
|
||||
imageBarrier.oldLayout = *imageLayout;
|
||||
imageBarrier.newLayout = newImageLayout;
|
||||
imageBarrier.image = image;
|
||||
imageBarrier.subresourceRange.aspectMask = aspectMask;
|
||||
imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageBarrier.subresourceRange.baseMipLevel = baseMip;
|
||||
imageBarrier.subresourceRange.levelCount = numMipLevels;
|
||||
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;
|
||||
|
||||
*imageLayout = newImageLayout;
|
||||
}
|
||||
|
||||
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) {
|
||||
VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
image_memory_barrier.srcAccessMask = srcAccessMask;
|
||||
image_memory_barrier.dstAccessMask = dstAccessMask;
|
||||
image_memory_barrier.oldLayout = oldImageLayout;
|
||||
image_memory_barrier.newLayout = newImageLayout;
|
||||
image_memory_barrier.image = image;
|
||||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = baseMip;
|
||||
image_memory_barrier.subresourceRange.levelCount = numMipLevels;
|
||||
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);
|
||||
void VulkanBarrierBatch::TransitionDepthStencilImageAuto(
|
||||
VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers) {
|
||||
_dbg_assert_(image != VK_NULL_HANDLE);
|
||||
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
VkAccessFlags dstAccessMask = 0;
|
||||
switch (*imageLayout) {
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
srcAccessMask = 0;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
// We only texture from images in the fragment shader, so can do this simply.
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(false, "Unexpected oldLayout: %s", VulkanImageLayoutToString(*imageLayout));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (newImageLayout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
dstStageMask_ |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(false, "Unexpected newLayout: %s", VulkanImageLayoutToString(newImageLayout));
|
||||
break;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier &imageBarrier = imageBarriers_.push_uninitialized();
|
||||
imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageBarrier.pNext = nullptr;
|
||||
imageBarrier.srcAccessMask = srcAccessMask;
|
||||
imageBarrier.dstAccessMask = dstAccessMask;
|
||||
imageBarrier.oldLayout = *imageLayout;
|
||||
imageBarrier.newLayout = newImageLayout;
|
||||
imageBarrier.image = image;
|
||||
imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
imageBarrier.subresourceRange.baseMipLevel = baseMip;
|
||||
imageBarrier.subresourceRange.levelCount = numMipLevels;
|
||||
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;
|
||||
|
||||
*imageLayout = newImageLayout;
|
||||
}
|
||||
|
||||
void VulkanBarrierBatch::TransitionColorImageAuto(VKRImage *image, VkImageLayout newImageLayout) {
|
||||
TransitionColorImageAuto(image->image, &image->layout, newImageLayout, 0, 1, image->numLayers);
|
||||
}
|
||||
|
||||
void VulkanBarrierBatch::TransitionDepthStencilImageAuto(VKRImage *image, VkImageLayout newImageLayout) {
|
||||
TransitionDepthStencilImageAuto(image->image, &image->layout, newImageLayout, 0, 1, image->numLayers);
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Common/Data/Collections/TinySet.h"
|
||||
|
||||
class VulkanContext;
|
||||
struct VKRImage;
|
||||
|
||||
class VulkanBarrierBatch {
|
||||
public:
|
||||
@@ -16,6 +17,7 @@ public:
|
||||
|
||||
bool empty() const { return imageBarriers_.empty(); }
|
||||
|
||||
// TODO: Replace this with TransitionImage.
|
||||
VkImageMemoryBarrier *Add(VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags) {
|
||||
srcStageMask_ |= srcStageMask;
|
||||
dstStageMask_ |= dstStageMask;
|
||||
@@ -44,8 +46,11 @@ 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, int numLayers, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout);
|
||||
void TransitionColorImageAuto(VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers);
|
||||
void TransitionDepthStencilImageAuto(VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers);
|
||||
|
||||
void TransitionColorImageAuto(VKRImage *image, VkImageLayout newImageLayout);
|
||||
void TransitionDepthStencilImageAuto(VKRImage *image, VkImageLayout newImageLayout);
|
||||
|
||||
void Flush(VkCommandBuffer cmd);
|
||||
|
||||
@@ -55,9 +60,3 @@ private:
|
||||
VkPipelineStageFlags dstStageMask_ = 0;
|
||||
VkDependencyFlags dependencyFlags_ = 0;
|
||||
};
|
||||
|
||||
// Detailed control, but just a single image. Use the barrier batch when possible.
|
||||
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);
|
||||
+181
-101
@@ -76,6 +76,20 @@ const char *VulkanPresentModeToString(VkPresentModeKHR presentMode) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *VulkanImageLayoutToString(VkImageLayout imageLayout) {
|
||||
switch (imageLayout) {
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED: return "UNDEFINED";
|
||||
case VK_IMAGE_LAYOUT_GENERAL: return "GENERAL";
|
||||
case VK_IMAGE_LAYOUT_PREINITIALIZED: return "PREINITIALIZED";
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return "TRANSFER_SRC_OPTIMAL";
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return "TRANSFER_DST_OPTIMAL";
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return "SHADER_READ_ONLY_OPTIMAL";
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return "COLOR_ATTACHMENT_OPTIMAL";
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return "DEPTH_STENCIL_ATTACHMENT_OPTIMAL";
|
||||
default: return "OTHER";
|
||||
}
|
||||
}
|
||||
|
||||
VulkanContext::VulkanContext() {
|
||||
// Do nothing here.
|
||||
}
|
||||
@@ -151,9 +165,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
}
|
||||
instance_extensions_enabled_.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
extensionsLookup_.EXT_debug_utils = true;
|
||||
INFO_LOG(G3D, "Vulkan debug_utils validation enabled.");
|
||||
INFO_LOG(Log::G3D, "Vulkan debug_utils validation enabled.");
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Validation layer extension not available - not enabling Vulkan validation.");
|
||||
ERROR_LOG(Log::G3D, "Validation layer extension not available - not enabling Vulkan validation.");
|
||||
flags_ &= ~VULKAN_FLAG_VALIDATE;
|
||||
}
|
||||
}
|
||||
@@ -161,19 +175,24 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
// Temporary hack for libretro. For some reason, when we try to load the functions from this extension,
|
||||
// we get null pointers when running libretro. Quite strange.
|
||||
#if !defined(__LIBRETRO__)
|
||||
if (EnableInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
|
||||
if (EnableInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_API_VERSION_1_1)) {
|
||||
extensionsLookup_.KHR_get_physical_device_properties2 = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (EnableInstanceExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME)) {
|
||||
if (EnableInstanceExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, 0)) {
|
||||
extensionsLookup_.EXT_swapchain_colorspace = true;
|
||||
}
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
if (EnableInstanceExtension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, 0)) {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// Validate that all the instance extensions we ask for are actually available.
|
||||
for (auto ext : instance_extensions_enabled_) {
|
||||
if (!IsInstanceExtensionAvailable(ext))
|
||||
WARN_LOG(G3D, "WARNING: Does not seem that instance extension '%s' is available. Trying to proceed anyway.", ext);
|
||||
WARN_LOG(Log::G3D, "WARNING: Does not seem that instance extension '%s' is available. Trying to proceed anyway.", ext);
|
||||
}
|
||||
|
||||
VkApplicationInfo app_info{ VK_STRUCTURE_TYPE_APPLICATION_INFO };
|
||||
@@ -192,6 +211,10 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
inst_info.enabledExtensionCount = (uint32_t)instance_extensions_enabled_.size();
|
||||
inst_info.ppEnabledExtensionNames = instance_extensions_enabled_.size() ? instance_extensions_enabled_.data() : nullptr;
|
||||
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
inst_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||
#endif
|
||||
|
||||
#if SIMULATE_VULKAN_FAILURE == 2
|
||||
VkResult res = VK_ERROR_INCOMPATIBLE_DRIVER;
|
||||
#else
|
||||
@@ -199,7 +222,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
#endif
|
||||
if (res != VK_SUCCESS) {
|
||||
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
|
||||
WARN_LOG(G3D, "Validation on but instance layer not available - dropping layers");
|
||||
WARN_LOG(Log::G3D, "Validation on but instance layer not available - dropping layers");
|
||||
// Drop the validation layers and try again.
|
||||
instance_layer_names_.clear();
|
||||
device_layer_names_.clear();
|
||||
@@ -207,9 +230,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
inst_info.ppEnabledLayerNames = nullptr;
|
||||
res = vkCreateInstance(&inst_info, nullptr, &instance_);
|
||||
if (res != VK_SUCCESS)
|
||||
ERROR_LOG(G3D, "Failed to create instance even without validation: %d", res);
|
||||
ERROR_LOG(Log::G3D, "Failed to create instance even without validation: %d", res);
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed to create instance : %d", res);
|
||||
ERROR_LOG(Log::G3D, "Failed to create instance : %d", res);
|
||||
}
|
||||
}
|
||||
if (res != VK_SUCCESS) {
|
||||
@@ -217,9 +240,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
return res;
|
||||
}
|
||||
|
||||
VulkanLoadInstanceFunctions(instance_, extensionsLookup_);
|
||||
VulkanLoadInstanceFunctions(instance_, extensionsLookup_, vulkanApiVersion_);
|
||||
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
|
||||
WARN_LOG(G3D, "CheckLayers for instance failed");
|
||||
WARN_LOG(Log::G3D, "CheckLayers for instance failed");
|
||||
// init_error_ = "Failed to validate instance layers";
|
||||
// return;
|
||||
}
|
||||
@@ -231,7 +254,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
res = vkEnumeratePhysicalDevices(instance_, &gpu_count, nullptr);
|
||||
#endif
|
||||
if (gpu_count <= 0) {
|
||||
ERROR_LOG(G3D, "Vulkan driver found but no supported GPU is available");
|
||||
ERROR_LOG(Log::G3D, "Vulkan driver found but no supported GPU is available");
|
||||
init_error_ = "No Vulkan physical devices found";
|
||||
vkDestroyInstance(instance_, nullptr);
|
||||
instance_ = nullptr;
|
||||
@@ -249,18 +272,18 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2) {
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceProperties2) {
|
||||
for (uint32_t i = 0; i < gpu_count; i++) {
|
||||
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};
|
||||
ChainStruct(props2, &pushProps);
|
||||
ChainStruct(props2, &extHostMemProps);
|
||||
ChainStruct(props2, &depthStencilResolveProps);
|
||||
vkGetPhysicalDeviceProperties2(physical_devices_[i], &props2);
|
||||
|
||||
props2.pNext = &pushProps;
|
||||
pushProps.pNext = &extHostMemProps;
|
||||
extHostMemProps.pNext = &depthStencilResolveProps;
|
||||
vkGetPhysicalDeviceProperties2KHR(physical_devices_[i], &props2);
|
||||
// Don't want bad pointers sitting around.
|
||||
// Don't want bad pointers sitting around. Probably not really necessary.
|
||||
props2.pNext = nullptr;
|
||||
pushProps.pNext = nullptr;
|
||||
extHostMemProps.pNext = nullptr;
|
||||
@@ -277,6 +300,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
}
|
||||
|
||||
if (extensionsLookup_.EXT_debug_utils) {
|
||||
_assert_(vkCreateDebugUtilsMessengerEXT != nullptr);
|
||||
InitDebugUtilsCallback();
|
||||
}
|
||||
|
||||
@@ -535,13 +559,39 @@ int VulkanContext::GetBestPhysicalDevice() {
|
||||
return best;
|
||||
}
|
||||
|
||||
void VulkanContext::ChooseDevice(int physical_device) {
|
||||
bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) {
|
||||
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
|
||||
return true;
|
||||
}
|
||||
for (auto &iter : device_extension_properties_) {
|
||||
if (!strcmp(iter.extensionName, extension)) {
|
||||
device_extensions_enabled_.push_back(extension);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VulkanContext::EnableInstanceExtension(const char *extension, uint32_t coreVersion) {
|
||||
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
|
||||
return true;
|
||||
}
|
||||
for (auto &iter : instance_extension_properties_) {
|
||||
if (!strcmp(iter.extensionName, extension)) {
|
||||
instance_extensions_enabled_.push_back(extension);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VkResult VulkanContext::CreateDevice(int physical_device) {
|
||||
physical_device_ = physical_device;
|
||||
INFO_LOG(G3D, "Chose physical device %d: %s", physical_device, physicalDeviceProperties_[physical_device].properties.deviceName);
|
||||
INFO_LOG(Log::G3D, "Chose physical device %d: %s", physical_device, physicalDeviceProperties_[physical_device].properties.deviceName);
|
||||
|
||||
GetDeviceLayerProperties();
|
||||
if (!CheckLayers(device_layer_properties_, device_layer_names_)) {
|
||||
WARN_LOG(G3D, "CheckLayers for device %d failed", physical_device);
|
||||
WARN_LOG(Log::G3D, "CheckLayers for device %d failed", physical_device);
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr);
|
||||
@@ -579,72 +629,24 @@ void VulkanContext::ChooseDevice(int physical_device) {
|
||||
// This is as good a place as any to do this. Though, we don't use this much anymore after we added
|
||||
// support for VMA.
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties_);
|
||||
INFO_LOG(G3D, "Memory Types (%d):", memory_properties_.memoryTypeCount);
|
||||
INFO_LOG(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)
|
||||
continue;
|
||||
INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties_.memoryTypes[i].heapIndex,
|
||||
INFO_LOG(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 };
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR };
|
||||
VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR };
|
||||
|
||||
features2.pNext = &multiViewFeatures;
|
||||
multiViewFeatures.pNext = &presentWaitFeatures;
|
||||
presentWaitFeatures.pNext = &presentIdFeatures;
|
||||
presentIdFeatures.pNext = nullptr;
|
||||
|
||||
vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2);
|
||||
deviceFeatures_.available.standard = features2.features;
|
||||
deviceFeatures_.available.multiview = multiViewFeatures;
|
||||
deviceFeatures_.available.presentWait = presentWaitFeatures;
|
||||
deviceFeatures_.available.presentId = presentIdFeatures;
|
||||
} else {
|
||||
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard);
|
||||
deviceFeatures_.available.multiview = {};
|
||||
}
|
||||
|
||||
GetDeviceLayerExtensionList(nullptr, device_extension_properties_);
|
||||
|
||||
device_extensions_enabled_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) {
|
||||
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
|
||||
return true;
|
||||
}
|
||||
for (auto &iter : device_extension_properties_) {
|
||||
if (!strcmp(iter.extensionName, extension)) {
|
||||
device_extensions_enabled_.push_back(extension);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VulkanContext::EnableInstanceExtension(const char *extension) {
|
||||
for (auto &iter : instance_extension_properties_) {
|
||||
if (!strcmp(iter.extensionName, extension)) {
|
||||
instance_extensions_enabled_.push_back(extension);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VkResult VulkanContext::CreateDevice() {
|
||||
if (!init_error_.empty() || physical_device_ < 0) {
|
||||
ERROR_LOG(G3D, "Vulkan init failed: %s", init_error_.c_str());
|
||||
ERROR_LOG(Log::G3D, "Vulkan init failed: %s", init_error_.c_str());
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -689,6 +691,44 @@ VkResult VulkanContext::CreateDevice() {
|
||||
extensionsLookup_.KHR_present_wait = EnableDeviceExtension(VK_KHR_PRESENT_WAIT_EXTENSION_NAME, 0);
|
||||
}
|
||||
|
||||
extensionsLookup_.EXT_provoking_vertex = EnableDeviceExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, 0);
|
||||
|
||||
// Optional features
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceFeatures2) {
|
||||
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 };
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR };
|
||||
VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR };
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertexFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT };
|
||||
|
||||
ChainStruct(features2, &multiViewFeatures);
|
||||
if (extensionsLookup_.KHR_present_wait) {
|
||||
ChainStruct(features2, &presentWaitFeatures);
|
||||
}
|
||||
if (extensionsLookup_.KHR_present_id) {
|
||||
ChainStruct(features2, &presentIdFeatures);
|
||||
}
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
ChainStruct(features2, &provokingVertexFeatures);
|
||||
}
|
||||
vkGetPhysicalDeviceFeatures2(physical_devices_[physical_device_], &features2);
|
||||
deviceFeatures_.available.standard = features2.features;
|
||||
deviceFeatures_.available.multiview = multiViewFeatures;
|
||||
if (extensionsLookup_.KHR_present_wait) {
|
||||
deviceFeatures_.available.presentWait = presentWaitFeatures;
|
||||
}
|
||||
if (extensionsLookup_.KHR_present_id) {
|
||||
deviceFeatures_.available.presentId = presentIdFeatures;
|
||||
}
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
deviceFeatures_.available.provokingVertex = provokingVertexFeatures;
|
||||
}
|
||||
} else {
|
||||
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard);
|
||||
deviceFeatures_.available.multiview = {};
|
||||
}
|
||||
|
||||
deviceFeatures_.enabled = {};
|
||||
// Enable a few safe ones if they are available.
|
||||
deviceFeatures_.enabled.standard.dualSrcBlend = deviceFeatures_.available.standard.dualSrcBlend;
|
||||
@@ -719,6 +759,11 @@ VkResult VulkanContext::CreateDevice() {
|
||||
if (extensionsLookup_.KHR_present_wait) {
|
||||
deviceFeatures_.enabled.presentWait.presentWait = deviceFeatures_.available.presentWait.presentWait;
|
||||
}
|
||||
deviceFeatures_.enabled.provokingVertex = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT };
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
deviceFeatures_.enabled.provokingVertex.provokingVertexLast = true;
|
||||
}
|
||||
|
||||
// deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader;
|
||||
|
||||
VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
|
||||
@@ -734,10 +779,16 @@ VkResult VulkanContext::CreateDevice() {
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2) {
|
||||
device_info.pNext = &features2;
|
||||
features2.features = deviceFeatures_.enabled.standard;
|
||||
features2.pNext = &deviceFeatures_.enabled.multiview;
|
||||
deviceFeatures_.enabled.multiview.pNext = &deviceFeatures_.enabled.presentWait;
|
||||
deviceFeatures_.enabled.presentWait.pNext = &deviceFeatures_.enabled.presentId;
|
||||
deviceFeatures_.enabled.presentId.pNext = nullptr;
|
||||
ChainStruct(features2, &deviceFeatures_.enabled.multiview);
|
||||
if (extensionsLookup_.KHR_present_wait) {
|
||||
ChainStruct(features2, &deviceFeatures_.enabled.presentWait);
|
||||
}
|
||||
if (extensionsLookup_.KHR_present_id) {
|
||||
ChainStruct(features2, &deviceFeatures_.enabled.presentId);
|
||||
}
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
ChainStruct(features2, &deviceFeatures_.enabled.provokingVertex);
|
||||
}
|
||||
} else {
|
||||
device_info.pEnabledFeatures = &deviceFeatures_.enabled.standard;
|
||||
}
|
||||
@@ -745,11 +796,11 @@ VkResult VulkanContext::CreateDevice() {
|
||||
VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_);
|
||||
if (res != VK_SUCCESS) {
|
||||
init_error_ = "Unable to create Vulkan device";
|
||||
ERROR_LOG(G3D, "Unable to create Vulkan device");
|
||||
ERROR_LOG(Log::G3D, "Unable to create Vulkan device");
|
||||
} else {
|
||||
VulkanLoadDeviceFunctions(device_, extensionsLookup_);
|
||||
VulkanLoadDeviceFunctions(device_, extensionsLookup_, vulkanApiVersion_);
|
||||
}
|
||||
INFO_LOG(G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName);
|
||||
INFO_LOG(Log::G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName);
|
||||
|
||||
// Since we successfully created a device (however we got here, might be interesting in debug), we force the choice to be visible in the menu.
|
||||
VulkanSetAvailable(true);
|
||||
@@ -820,15 +871,40 @@ VkResult VulkanContext::InitDebugUtilsCallback() {
|
||||
VkDebugUtilsMessengerEXT messenger;
|
||||
VkResult res = vkCreateDebugUtilsMessengerEXT(instance_, &callback1, nullptr, &messenger);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "Failed to register debug callback with vkCreateDebugUtilsMessengerEXT");
|
||||
ERROR_LOG(Log::G3D, "Failed to register debug callback with vkCreateDebugUtilsMessengerEXT");
|
||||
// Do error handling for VK_ERROR_OUT_OF_MEMORY
|
||||
} else {
|
||||
INFO_LOG(G3D, "Debug callback registered with vkCreateDebugUtilsMessengerEXT.");
|
||||
INFO_LOG(Log::G3D, "Debug callback registered with vkCreateDebugUtilsMessengerEXT.");
|
||||
utils_callbacks.push_back(messenger);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool VulkanContext::CreateInstanceAndDevice(const CreateInfo &info) {
|
||||
VkResult res = CreateInstance(info);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(Log::G3D, "Failed to create vulkan context: %s", InitError().c_str());
|
||||
VulkanSetAvailable(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
int physicalDevice = GetBestPhysicalDevice();
|
||||
if (physicalDevice < 0) {
|
||||
ERROR_LOG(Log::G3D, "No usable Vulkan device found.");
|
||||
DestroyInstance();
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(Log::G3D, "Creating Vulkan device (flags: %08x)", info.flags);
|
||||
if (CreateDevice(physicalDevice) != VK_SUCCESS) {
|
||||
INFO_LOG(Log::G3D, "Failed to create vulkan device: %s", InitError().c_str());
|
||||
DestroyInstance();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanContext::SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name) {
|
||||
VkDebugUtilsObjectNameInfoEXT info{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT };
|
||||
info.pObjectName = name;
|
||||
@@ -846,12 +922,12 @@ VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data
|
||||
|
||||
VkResult VulkanContext::ReinitSurface() {
|
||||
if (surface_ != VK_NULL_HANDLE) {
|
||||
INFO_LOG(G3D, "Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height);
|
||||
INFO_LOG(Log::G3D, "Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height);
|
||||
vkDestroySurfaceKHR(instance_, surface_, nullptr);
|
||||
surface_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Creating Vulkan surface for window (%p %p)", winsysData1_, winsysData2_);
|
||||
INFO_LOG(Log::G3D, "Creating Vulkan surface for window (data1=%p data2=%p)", winsysData1_, winsysData2_);
|
||||
|
||||
VkResult retval = VK_SUCCESS;
|
||||
|
||||
@@ -1171,7 +1247,7 @@ bool VulkanContext::ChooseQueue() {
|
||||
|
||||
// Generate error if could not find both a graphics and a present queue
|
||||
if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
|
||||
ERROR_LOG(G3D, "Could not find a graphics and a present queue");
|
||||
ERROR_LOG(Log::G3D, "Could not find a graphics and a present queue");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1195,7 +1271,7 @@ bool VulkanContext::ChooseQueue() {
|
||||
// the surface has no preferred format. Otherwise, at least one
|
||||
// supported format will be returned.
|
||||
if (formatCount == 0 || (formatCount == 1 && surfFormats_[0].format == VK_FORMAT_UNDEFINED)) {
|
||||
INFO_LOG(G3D, "swapchain_format: Falling back to B8G8R8A8_UNORM");
|
||||
INFO_LOG(Log::G3D, "swapchain_format: Falling back to B8G8R8A8_UNORM");
|
||||
swapchainFormat_ = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
} else {
|
||||
swapchainFormat_ = VK_FORMAT_UNDEFINED;
|
||||
@@ -1212,7 +1288,7 @@ bool VulkanContext::ChooseQueue() {
|
||||
// Okay, take the first one then.
|
||||
swapchainFormat_ = surfFormats_[0].format;
|
||||
}
|
||||
INFO_LOG(G3D, "swapchain_format: %d (/%d)", swapchainFormat_, formatCount);
|
||||
INFO_LOG(Log::G3D, "swapchain_format: %d (/%d)", swapchainFormat_, formatCount);
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_);
|
||||
@@ -1244,14 +1320,14 @@ static std::string surface_transforms_to_string(VkSurfaceTransformFlagsKHR trans
|
||||
bool VulkanContext::InitSwapchain() {
|
||||
_assert_(physical_device_ >= 0 && physical_device_ < physical_devices_.size());
|
||||
if (!surface_) {
|
||||
ERROR_LOG(G3D, "VK: No surface, can't create swapchain");
|
||||
ERROR_LOG(Log::G3D, "VK: No surface, can't create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_);
|
||||
if (res == VK_ERROR_SURFACE_LOST_KHR) {
|
||||
// Not much to do.
|
||||
ERROR_LOG(G3D, "VK: Surface lost in InitSwapchain");
|
||||
ERROR_LOG(Log::G3D, "VK: Surface lost in InitSwapchain");
|
||||
return false;
|
||||
}
|
||||
_dbg_assert_(res == VK_SUCCESS);
|
||||
@@ -1266,7 +1342,11 @@ bool VulkanContext::InitSwapchain() {
|
||||
VkExtent2D currentExtent { surfCapabilities_.currentExtent };
|
||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSurfaceCapabilitiesKHR.html
|
||||
// currentExtent is the current width and height of the surface, or the special value (0xFFFFFFFF, 0xFFFFFFFF) indicating that the surface size will be determined by the extent of a swapchain targeting the surface.
|
||||
if (currentExtent.width == 0xFFFFFFFFu || currentExtent.height == 0xFFFFFFFFu) {
|
||||
if (currentExtent.width == 0xFFFFFFFFu || currentExtent.height == 0xFFFFFFFFu
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
|| currentExtent.width == 0 || currentExtent.height == 0
|
||||
#endif
|
||||
) {
|
||||
_dbg_assert_((bool)cbGetDrawSize_)
|
||||
if (cbGetDrawSize_) {
|
||||
currentExtent = cbGetDrawSize_();
|
||||
@@ -1276,7 +1356,7 @@ bool VulkanContext::InitSwapchain() {
|
||||
swapChainExtent_.width = clamp(currentExtent.width, surfCapabilities_.minImageExtent.width, surfCapabilities_.maxImageExtent.width);
|
||||
swapChainExtent_.height = clamp(currentExtent.height, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.height);
|
||||
|
||||
INFO_LOG(G3D, "surfCapabilities_.current: %dx%d min: %dx%d max: %dx%d computed: %dx%d",
|
||||
INFO_LOG(Log::G3D, "surfCapabilities_.current: %dx%d min: %dx%d max: %dx%d computed: %dx%d",
|
||||
currentExtent.width, currentExtent.height,
|
||||
surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height,
|
||||
surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height,
|
||||
@@ -1295,7 +1375,7 @@ bool VulkanContext::InitSwapchain() {
|
||||
availablePresentModes_.push_back(presentModes[i]);
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Supported present modes: %s", modes.c_str());
|
||||
INFO_LOG(Log::G3D, "Supported present modes: %s", modes.c_str());
|
||||
for (size_t i = 0; i < presentModeCount; i++) {
|
||||
bool match = false;
|
||||
match = match || ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR);
|
||||
@@ -1323,7 +1403,7 @@ bool VulkanContext::InitSwapchain() {
|
||||
desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Chosen present mode: %d (%s). numSwapChainImages: %d/%d",
|
||||
INFO_LOG(Log::G3D, "Chosen present mode: %d (%s). numSwapChainImages: %d/%d",
|
||||
swapchainPresentMode, VulkanPresentModeToString(swapchainPresentMode),
|
||||
desiredNumberOfSwapChainImages, surfCapabilities_.maxImageCount);
|
||||
|
||||
@@ -1370,13 +1450,13 @@ bool VulkanContext::InitSwapchain() {
|
||||
}
|
||||
|
||||
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());
|
||||
INFO_LOG(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) {
|
||||
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);
|
||||
INFO_LOG(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.
|
||||
@@ -1386,7 +1466,7 @@ bool VulkanContext::InitSwapchain() {
|
||||
// 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);
|
||||
INFO_LOG(Log::G3D, "PowerVR driver version new enough (%08x), not applying swapchain width hack", driverVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1430,10 +1510,10 @@ bool VulkanContext::InitSwapchain() {
|
||||
|
||||
res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swapchain_);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "vkCreateSwapchainKHR failed!");
|
||||
ERROR_LOG(Log::G3D, "vkCreateSwapchainKHR failed!");
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(G3D, "Created swapchain: %dx%d", swap_chain_info.imageExtent.width, swap_chain_info.imageExtent.height);
|
||||
INFO_LOG(Log::G3D, "Created swapchain: %dx%d", swap_chain_info.imageExtent.width, swap_chain_info.imageExtent.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1458,17 +1538,17 @@ void VulkanContext::PerformPendingDeletes() {
|
||||
|
||||
void VulkanContext::DestroyDevice() {
|
||||
if (swapchain_) {
|
||||
ERROR_LOG(G3D, "DestroyDevice: Swapchain should have been destroyed.");
|
||||
ERROR_LOG(Log::G3D, "DestroyDevice: Swapchain should have been destroyed.");
|
||||
}
|
||||
if (surface_) {
|
||||
ERROR_LOG(G3D, "DestroyDevice: Surface should have been destroyed.");
|
||||
ERROR_LOG(Log::G3D, "DestroyDevice: Surface should have been destroyed.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(frame_); i++) {
|
||||
frame_[i].profiler.Shutdown();
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "VulkanContext::DestroyDevice (performing deletes)");
|
||||
INFO_LOG(Log::G3D, "VulkanContext::DestroyDevice (performing deletes)");
|
||||
PerformPendingDeletes();
|
||||
|
||||
vmaDestroyAllocator(allocator_);
|
||||
@@ -1760,9 +1840,9 @@ void VulkanContext::GetImageMemoryRequirements(VkImage image, VkMemoryRequiremen
|
||||
|
||||
VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR};
|
||||
VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR};
|
||||
memReq2.pNext = &memDedicatedReq;
|
||||
ChainStruct(memReq2, &memDedicatedReq);
|
||||
|
||||
vkGetImageMemoryRequirements2KHR(GetDevice(), &memReqInfo2, &memReq2);
|
||||
vkGetImageMemoryRequirements2(GetDevice(), &memReqInfo2, &memReq2);
|
||||
|
||||
*mem_reqs = memReq2.memoryRequirements;
|
||||
*dedicatedAllocation =
|
||||
|
||||
@@ -44,6 +44,11 @@ VK_DEFINE_HANDLE(VmaAllocation);
|
||||
|
||||
std::string VulkanVendorString(uint32_t vendorId);
|
||||
|
||||
template<class R, class T> inline void ChainStruct(R &root, T *newStruct) {
|
||||
newStruct->pNext = root.pNext;
|
||||
root.pNext = newStruct;
|
||||
}
|
||||
|
||||
// Not all will be usable on all platforms, of course...
|
||||
enum WindowSystem {
|
||||
#ifdef _WIN32
|
||||
@@ -181,11 +186,17 @@ public:
|
||||
|
||||
int GetBestPhysicalDevice();
|
||||
int GetPhysicalDeviceByName(const std::string &name);
|
||||
void ChooseDevice(int physical_device);
|
||||
bool EnableInstanceExtension(const char *extension);
|
||||
// The core version is to avoid enabling extensions that are merged into core Vulkan from a certain version.
|
||||
|
||||
// Convenience method to avoid code duplication.
|
||||
// If it returns false, delete the context.
|
||||
bool CreateInstanceAndDevice(const CreateInfo &info);
|
||||
|
||||
// The coreVersion is to avoid enabling extensions that are merged into core Vulkan from a certain version.
|
||||
bool EnableInstanceExtension(const char *extension, uint32_t coreVersion);
|
||||
bool EnableDeviceExtension(const char *extension, uint32_t coreVersion);
|
||||
VkResult CreateDevice();
|
||||
|
||||
// Was previously two functions, ChooseDevice and CreateDevice.
|
||||
VkResult CreateDevice(int physical_device);
|
||||
|
||||
const std::string &InitError() const { return init_error_; }
|
||||
|
||||
@@ -273,6 +284,7 @@ public:
|
||||
VkPhysicalDeviceMultiviewFeatures multiview;
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR presentWait;
|
||||
VkPhysicalDevicePresentIdFeaturesKHR presentId;
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertex;
|
||||
};
|
||||
|
||||
const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const {
|
||||
@@ -417,7 +429,7 @@ private:
|
||||
|
||||
bool CheckLayers(const std::vector<LayerProperties> &layer_props, const std::vector<const char *> &layer_names) const;
|
||||
|
||||
WindowSystem winsys_;
|
||||
WindowSystem winsys_{};
|
||||
|
||||
// Don't use the real types here to avoid having to include platform-specific stuff
|
||||
// that we really don't want in everything that uses VulkanContext.
|
||||
@@ -481,7 +493,7 @@ private:
|
||||
std::vector<VkDebugUtilsMessengerEXT> utils_callbacks;
|
||||
|
||||
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
|
||||
VkFormat swapchainFormat_;
|
||||
VkFormat swapchainFormat_ = VK_FORMAT_UNDEFINED;
|
||||
|
||||
uint32_t queue_count = 0;
|
||||
|
||||
@@ -490,7 +502,7 @@ private:
|
||||
VkSurfaceCapabilitiesKHR surfCapabilities_{};
|
||||
std::vector<VkSurfaceFormatKHR> surfFormats_{};
|
||||
|
||||
VkPresentModeKHR presentMode_;
|
||||
VkPresentModeKHR presentMode_ = VK_PRESENT_MODE_FIFO_KHR;
|
||||
std::vector<VkPresentModeKHR> availablePresentModes_;
|
||||
|
||||
std::vector<VkCommandBuffer> cmdQueue_;
|
||||
@@ -513,6 +525,7 @@ bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *sourceCode,
|
||||
const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace);
|
||||
const char *VulkanFormatToString(VkFormat format);
|
||||
const char *VulkanPresentModeToString(VkPresentModeKHR presentMode);
|
||||
const char *VulkanImageLayoutToString(VkImageLayout imageLayout);
|
||||
|
||||
std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props);
|
||||
|
||||
|
||||
@@ -62,13 +62,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 606910136:
|
||||
case -392708513:
|
||||
case -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;
|
||||
case -375211665:
|
||||
// VUID-vkAllocateMemory-pAllocateInfo-01713
|
||||
// Can happen when VMA aggressively tries to allocate aperture memory for upload. It gracefully
|
||||
@@ -128,7 +121,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
|
||||
count = g_errorCount[messageCode]++;
|
||||
}
|
||||
if (count == MAX_SAME_ERROR_COUNT) {
|
||||
WARN_LOG(G3D, "Too many validation messages with message %d, stopping", messageCode);
|
||||
WARN_LOG(Log::G3D, "Too many validation messages with message %d, stopping", messageCode);
|
||||
}
|
||||
if (count >= MAX_SAME_ERROR_COUNT) {
|
||||
return false;
|
||||
@@ -173,9 +166,9 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
|
||||
#endif
|
||||
|
||||
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
ERROR_LOG(G3D, "VKDEBUG: %s", msg.c_str());
|
||||
ERROR_LOG(Log::G3D, "VKDEBUG: %s", msg.c_str());
|
||||
} else {
|
||||
WARN_LOG(G3D, "VKDEBUG: %s", msg.c_str());
|
||||
WARN_LOG(Log::G3D, "VKDEBUG: %s", msg.c_str());
|
||||
}
|
||||
|
||||
// false indicates that layer should not bail-out of an
|
||||
|
||||
@@ -56,7 +56,7 @@ bool VulkanDescSetPool::Allocate(VkDescriptorSet *descriptorSets, int count, con
|
||||
VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, descriptorSets);
|
||||
|
||||
if (result == VK_ERROR_FRAGMENTED_POOL || result < 0) {
|
||||
WARN_LOG(G3D, "Pool %s %s - recreating", tag_, result == VK_ERROR_FRAGMENTED_POOL ? "fragmented" : "full");
|
||||
WARN_LOG(Log::G3D, "Pool %s %s - recreating", tag_, result == VK_ERROR_FRAGMENTED_POOL ? "fragmented" : "full");
|
||||
// There seems to have been a spec revision. Here we should apparently recreate the descriptor pool,
|
||||
// so let's do that. See https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkAllocateDescriptorSets.html
|
||||
// Fragmentation shouldn't really happen though since we wipe the pool every frame.
|
||||
@@ -113,7 +113,7 @@ VkResult VulkanDescSetPool::Recreate(bool grow) {
|
||||
|
||||
// Delete the pool if it already exists.
|
||||
if (descPool_ != VK_NULL_HANDLE) {
|
||||
INFO_LOG(G3D, "Reallocating %s desc pool from %d to %d", tag_, prevSize, info_.maxSets);
|
||||
INFO_LOG(Log::G3D, "Reallocating %s desc pool from %d to %d", tag_, prevSize, info_.maxSets);
|
||||
vulkan_->Delete().QueueDeleteDescriptorPool(descPool_);
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#if 0 // def _DEBUG
|
||||
#define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__)
|
||||
#define VLOG(...) NOTICE_LOG(Log::G3D, __VA_ARGS__)
|
||||
#else
|
||||
#define VLOG(...)
|
||||
#endif
|
||||
@@ -90,17 +90,17 @@ void FrameData::AcquireNextImage(VulkanContext *vulkan) {
|
||||
case VK_SUBOPTIMAL_KHR:
|
||||
hasAcquired = true;
|
||||
// Hopefully the resize will happen shortly. Ignore - one frame might look bad or something.
|
||||
WARN_LOG(G3D, "VK_SUBOPTIMAL_KHR returned - ignoring");
|
||||
WARN_LOG(Log::G3D, "VK_SUBOPTIMAL_KHR returned - ignoring");
|
||||
break;
|
||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||
case VK_TIMEOUT:
|
||||
case VK_NOT_READY:
|
||||
// We do not set hasAcquired here!
|
||||
WARN_LOG(G3D, "%s returned from AcquireNextImage - processing the frame, but not presenting", VulkanResultToString(res));
|
||||
WARN_LOG(Log::G3D, "%s returned from AcquireNextImage - processing the frame, but not presenting", VulkanResultToString(res));
|
||||
skipSwap = true;
|
||||
break;
|
||||
case VK_ERROR_SURFACE_LOST_KHR:
|
||||
ERROR_LOG(G3D, "%s returned from AcquireNextImage - ignoring, but this better be during shutdown", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "%s returned from AcquireNextImage - ignoring, but this better be during shutdown", VulkanResultToString(res));
|
||||
skipSwap = true;
|
||||
break;
|
||||
default:
|
||||
@@ -132,13 +132,13 @@ VkResult FrameData::QueuePresent(VulkanContext *vulkan, FrameDataShared &shared)
|
||||
|
||||
if (shared.measurePresentTime) {
|
||||
if (vulkan->Extensions().KHR_present_id && vulkan->GetDeviceFeatures().enabled.presentId.presentId) {
|
||||
ChainStruct(present, &presentID);
|
||||
presentID.pPresentIds = &frameId;
|
||||
presentID.swapchainCount = 1;
|
||||
present.pNext = &presentID;
|
||||
} else if (vulkan->Extensions().GOOGLE_display_timing) {
|
||||
ChainStruct(present, &presentGOOGLE);
|
||||
presentGOOGLE.pTimes = &presentTimeGOOGLE;
|
||||
presentGOOGLE.swapchainCount = 1;
|
||||
present.pNext = &presentGOOGLE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,10 +208,11 @@ void FrameData::Submit(VulkanContext *vulkan, FrameSubmitType type, FrameDataSha
|
||||
|
||||
cmdBufs[numCmdBufs++] = presentCmd;
|
||||
hasPresentCommands = false;
|
||||
}
|
||||
|
||||
if (type == FrameSubmitType::FinishFrame) {
|
||||
fenceToTrigger = fence;
|
||||
}
|
||||
if (type == FrameSubmitType::FinishFrame) {
|
||||
_dbg_assert_(!fenceToTrigger);
|
||||
fenceToTrigger = fence;
|
||||
}
|
||||
|
||||
if (!numCmdBufs && fenceToTrigger == VK_NULL_HANDLE) {
|
||||
|
||||
@@ -117,7 +117,7 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas
|
||||
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)", (void *)depth.image, (void *)depth.texAllLayersView, depth.format, tag_.c_str(), width, height);
|
||||
WARN_LOG(Log::G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", (void *)depth.image, (void *)depth.texAllLayersView, depth.format, tag_.c_str(), width, height);
|
||||
// Will probably crash, depending on driver.
|
||||
}
|
||||
views[attachmentCount++] = depth.rtView;
|
||||
@@ -505,7 +505,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
|
||||
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;
|
||||
ChainStruct(subpass2, &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;
|
||||
@@ -524,7 +524,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
|
||||
rp2.pCorrelatedViewMasks = multiview ? &viewMask : nullptr;
|
||||
rp2.pSubpasses = &subpass2;
|
||||
rp2.subpassCount = 1;
|
||||
res = vkCreateRenderPass2KHR(vulkan->GetDevice(), &rp2, nullptr, &pass);
|
||||
res = vkCreateRenderPass2(vulkan->GetDevice(), &rp2, nullptr, &pass);
|
||||
} else {
|
||||
res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass);
|
||||
}
|
||||
|
||||
@@ -38,14 +38,14 @@ static bool IsDepthStencilFormat(VkFormat format) {
|
||||
}
|
||||
}
|
||||
|
||||
bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
|
||||
bool VulkanTexture::CreateDirect(int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, VulkanBarrierBatch *barrierBatch, const VkComponentMapping *mapping) {
|
||||
if (w == 0 || h == 0 || numMips == 0) {
|
||||
ERROR_LOG(G3D, "Can't create a zero-size VulkanTexture");
|
||||
ERROR_LOG(Log::G3D, "Can't create a zero-size VulkanTexture");
|
||||
return false;
|
||||
}
|
||||
int maxDim = vulkan_->GetPhysicalDeviceProperties(0).properties.limits.maxImageDimension2D;
|
||||
if (w > maxDim || h > maxDim) {
|
||||
ERROR_LOG(G3D, "Can't create a texture this large");
|
||||
ERROR_LOG(Log::G3D, "Can't create a texture this large");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -113,10 +113,10 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i
|
||||
_assert_(false);
|
||||
break;
|
||||
}
|
||||
TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
barrierBatch->TransitionImage(image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, initialLayout,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage,
|
||||
0, dstAccessFlags);
|
||||
0, dstAccessFlags,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage);
|
||||
}
|
||||
|
||||
// Create the view while we're at it.
|
||||
@@ -137,7 +137,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i
|
||||
|
||||
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view_);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "vkCreateImageView failed: %s. Destroying image.", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "vkCreateImageView failed: %s. Destroying image.", VulkanResultToString(res));
|
||||
_assert_msg_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS, "%d", (int)res);
|
||||
vmaDestroyImage(vulkan_->Allocator(), image_, allocation_);
|
||||
view_ = VK_NULL_HANDLE;
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
// Fast uploads from buffer. Mipmaps supported.
|
||||
// Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
|
||||
// When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
|
||||
bool CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
|
||||
bool CreateDirect(int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, VulkanBarrierBatch *barrierBatch, const VkComponentMapping *mapping = nullptr);
|
||||
void ClearMip(VkCommandBuffer cmd, int mip, uint32_t value);
|
||||
|
||||
// Can also be used to copy individual levels of a 3D texture.
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#endif
|
||||
|
||||
namespace PPSSPP_VK {
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
PFN_vkCreateInstance vkCreateInstance;
|
||||
PFN_vkDestroyInstance vkDestroyInstance;
|
||||
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
|
||||
@@ -74,10 +75,8 @@ PFN_vkBindBufferMemory2 vkBindBufferMemory2;
|
||||
PFN_vkBindImageMemory vkBindImageMemory;
|
||||
PFN_vkBindImageMemory2 vkBindImageMemory2;
|
||||
PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
|
||||
PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2;
|
||||
PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements;
|
||||
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
|
||||
PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2;
|
||||
PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements;
|
||||
PFN_vkCreateFence vkCreateFence;
|
||||
PFN_vkDestroyFence vkDestroyFence;
|
||||
@@ -233,20 +232,23 @@ PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
|
||||
PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
|
||||
|
||||
// Assorted other extensions.
|
||||
PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
|
||||
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
||||
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
|
||||
PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
|
||||
PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR;
|
||||
PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2;
|
||||
PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2;
|
||||
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
|
||||
PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
|
||||
PFN_vkCreateRenderPass2 vkCreateRenderPass2;
|
||||
|
||||
PFN_vkWaitForPresentKHR vkWaitForPresentKHR;
|
||||
PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE;
|
||||
PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE;
|
||||
|
||||
#endif
|
||||
} // namespace PPSSPP_VK
|
||||
|
||||
using namespace PPSSPP_VK;
|
||||
|
||||
#if PPSSPP_PLATFORM(SWITCH)
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
// Statically linked MoltenVK
|
||||
#elif PPSSPP_PLATFORM(SWITCH)
|
||||
typedef void *VulkanLibraryHandle;
|
||||
static VulkanLibraryHandle vulkanLibrary;
|
||||
#define dlsym(x, y) nullptr
|
||||
@@ -262,23 +264,35 @@ static VulkanLibraryHandle vulkanLibrary;
|
||||
bool g_vulkanAvailabilityChecked = false;
|
||||
bool g_vulkanMayBeAvailable = false;
|
||||
|
||||
#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {INFO_LOG(G3D, "Missing (instance): %s", #x);}
|
||||
#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {INFO_LOG(G3D, "Missing (device): %s", #x);}
|
||||
#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(G3D,"Missing (global): %s", #x);}
|
||||
#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {INFO_LOG(Log::G3D, "Missing (instance): %s", #x);}
|
||||
#define LOAD_INSTANCE_FUNC_CORE(instance, x, ext_x, min_core) \
|
||||
x = (PFN_ ## x)vkGetInstanceProcAddr(instance, vulkanApiVersion >= min_core ? #x : #ext_x); \
|
||||
if (vulkanApiVersion >= min_core && !x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #ext_x); \
|
||||
if (!x) {INFO_LOG(Log::G3D, "Missing (instance): %s (%s)", #x, #ext_x);}
|
||||
#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {INFO_LOG(Log::G3D, "Missing (device): %s", #x);}
|
||||
#define LOAD_DEVICE_FUNC_CORE(instance, x, ext_x, min_core) \
|
||||
x = (PFN_ ## x)vkGetDeviceProcAddr(instance, vulkanApiVersion >= min_core ? #x : #ext_x); \
|
||||
if (vulkanApiVersion >= min_core && !x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #ext_x); \
|
||||
if (!x) {INFO_LOG(Log::G3D, "Missing (device): %s (%s)", #x, #ext_x);}
|
||||
#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(Log::G3D,"Missing (global): %s", #x);}
|
||||
|
||||
#define LOAD_GLOBAL_FUNC_LOCAL(lib, x) (PFN_ ## x)dlsym(lib, #x);
|
||||
|
||||
static const char * const device_name_blacklist[] = {
|
||||
"NVIDIA:SHIELD Tablet K1",
|
||||
"SDL:Horizon",
|
||||
"motorola:moto g54 5G", // See issue #18681 / #17825
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
static const char * const so_names[] = {
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
#elif PPSSPP_PLATFORM(IOS)
|
||||
"@executable_path/Frameworks/libMoltenVK.dylib",
|
||||
"MoltenVK",
|
||||
#elif PPSSPP_PLATFORM(MAC)
|
||||
"@executable_path/../Frameworks/libMoltenVK.dylib",
|
||||
"MoltenVK",
|
||||
#else
|
||||
"libvulkan.so",
|
||||
#if !defined(__ANDROID__)
|
||||
@@ -288,6 +302,7 @@ static const char * const so_names[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) {
|
||||
#if PPSSPP_PLATFORM(SWITCH)
|
||||
// Always unavailable, for now.
|
||||
@@ -323,9 +338,9 @@ static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) {
|
||||
(std::string(driverPath.c_str()) + "/").c_str(), driverLibName.c_str(),
|
||||
(std::string(fileRedirectDir.c_str()) + "/").c_str(), nullptr);
|
||||
if (!lib) {
|
||||
ERROR_LOG(G3D, "Failed to load custom driver with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str());
|
||||
ERROR_LOG(Log::G3D, "Failed to load custom driver with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str());
|
||||
} else {
|
||||
INFO_LOG(G3D, "Vulkan library loaded with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str());
|
||||
INFO_LOG(Log::G3D, "Vulkan library loaded with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,15 +350,17 @@ static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) {
|
||||
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
|
||||
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
|
||||
if (lib) {
|
||||
INFO_LOG(G3D, "Vulkan library loaded ('%s')", so_names[i]);
|
||||
INFO_LOG(Log::G3D, "Vulkan library loaded ('%s')", so_names[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lib;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
static void VulkanFreeLibrary(VulkanLibraryHandle &h) {
|
||||
if (h) {
|
||||
#if PPSSPP_PLATFORM(SWITCH)
|
||||
@@ -356,14 +373,21 @@ static void VulkanFreeLibrary(VulkanLibraryHandle &h) {
|
||||
h = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void VulkanSetAvailable(bool available) {
|
||||
INFO_LOG(G3D, "Setting Vulkan availability to true");
|
||||
INFO_LOG(Log::G3D, "Setting Vulkan availability to true");
|
||||
g_vulkanAvailabilityChecked = true;
|
||||
g_vulkanMayBeAvailable = available;
|
||||
}
|
||||
|
||||
bool VulkanMayBeAvailable() {
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
g_vulkanAvailabilityChecked = true;
|
||||
// MoltenVK does no longer seem to support iOS <= 12, despite what the docs say.
|
||||
g_vulkanMayBeAvailable = System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 13;
|
||||
return g_vulkanMayBeAvailable;
|
||||
#else
|
||||
// Unsupported in VR at the moment
|
||||
if (IsVREnabled()) {
|
||||
return false;
|
||||
@@ -376,18 +400,18 @@ bool VulkanMayBeAvailable() {
|
||||
std::string name = System_GetProperty(SYSPROP_NAME);
|
||||
for (const char *blacklisted_name : device_name_blacklist) {
|
||||
if (!strcmp(name.c_str(), blacklisted_name)) {
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Device blacklisted ('%s')", name.c_str());
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Device blacklisted ('%s')", name.c_str());
|
||||
g_vulkanAvailabilityChecked = true;
|
||||
g_vulkanMayBeAvailable = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Device allowed ('%s')", name.c_str());
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Device allowed ('%s')", name.c_str());
|
||||
|
||||
std::string errorStr;
|
||||
VulkanLibraryHandle lib = VulkanLoadLibrary(&errorStr);
|
||||
if (!lib) {
|
||||
INFO_LOG(G3D, "Vulkan loader: Library not available: %s", errorStr.c_str());
|
||||
INFO_LOG(Log::G3D, "Vulkan loader: Library not available: %s", errorStr.c_str());
|
||||
g_vulkanAvailabilityChecked = true;
|
||||
g_vulkanMayBeAvailable = false;
|
||||
return false;
|
||||
@@ -427,32 +451,32 @@ bool VulkanMayBeAvailable() {
|
||||
#endif
|
||||
|
||||
if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) {
|
||||
WARN_LOG(G3D, "VulkanMayBeAvailable: Function pointer missing, bailing");
|
||||
WARN_LOG(Log::G3D, "VulkanMayBeAvailable: Function pointer missing, bailing");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Enumerating instance extensions");
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Enumerating instance extensions");
|
||||
res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr);
|
||||
// Maximum paranoia.
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res));
|
||||
goto bail;
|
||||
}
|
||||
if (instanceExtCount == 0) {
|
||||
ERROR_LOG(G3D, "No VK instance extensions - won't be able to present.");
|
||||
ERROR_LOG(Log::G3D, "No VK instance extensions - won't be able to present.");
|
||||
goto bail;
|
||||
}
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount);
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount);
|
||||
instanceExts.resize(instanceExtCount);
|
||||
res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data());
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res));
|
||||
goto bail;
|
||||
}
|
||||
for (const auto &iter : instanceExts) {
|
||||
INFO_LOG(G3D, "VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion);
|
||||
INFO_LOG(Log::G3D, "VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion);
|
||||
if (platformSurfaceExtension && !strcmp(iter.extensionName, platformSurfaceExtension)) {
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension);
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension);
|
||||
instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension;
|
||||
platformSurfaceExtensionFound = true;
|
||||
break;
|
||||
@@ -463,19 +487,19 @@ bool VulkanMayBeAvailable() {
|
||||
}
|
||||
if (platformSurfaceExtension) {
|
||||
if (!platformSurfaceExtensionFound || !surfaceExtensionFound) {
|
||||
ERROR_LOG(G3D, "Platform surface extension not found");
|
||||
ERROR_LOG(Log::G3D, "Platform surface extension not found");
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
if (!surfaceExtensionFound) {
|
||||
ERROR_LOG(G3D, "Surface extension not found");
|
||||
ERROR_LOG(Log::G3D, "Surface extension not found");
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
// This can't happen unless the driver is double-reporting a surface extension.
|
||||
if (ci.enabledExtensionCount > 2) {
|
||||
ERROR_LOG(G3D, "Unexpected number of enabled instance extensions");
|
||||
ERROR_LOG(Log::G3D, "Unexpected number of enabled instance extensions");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
@@ -488,27 +512,27 @@ bool VulkanMayBeAvailable() {
|
||||
info.pEngineName = "VulkanCheckerEngine";
|
||||
ci.pApplicationInfo = &info;
|
||||
ci.flags = 0;
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Calling vkCreateInstance");
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Calling vkCreateInstance");
|
||||
res = localCreateInstance(&ci, nullptr, &instance);
|
||||
if (res != VK_SUCCESS) {
|
||||
instance = nullptr;
|
||||
ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to create vulkan instance (%s)", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: Failed to create vulkan instance (%s)", VulkanResultToString(res));
|
||||
goto bail;
|
||||
}
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Vulkan test instance created successfully.");
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Vulkan test instance created successfully.");
|
||||
res = localEnumerate(instance, &physicalDeviceCount, nullptr);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to count physical devices (%s)", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: Failed to count physical devices (%s)", VulkanResultToString(res));
|
||||
goto bail;
|
||||
}
|
||||
if (physicalDeviceCount == 0) {
|
||||
ERROR_LOG(G3D, "VulkanMayBeAvailable: No physical Vulkan devices (count = 0).");
|
||||
ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: No physical Vulkan devices (count = 0).");
|
||||
goto bail;
|
||||
}
|
||||
devices.resize(physicalDeviceCount);
|
||||
res = localEnumerate(instance, &physicalDeviceCount, devices.data());
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to enumerate physical devices (%s)", VulkanResultToString(res));
|
||||
ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: Failed to enumerate physical devices (%s)", VulkanResultToString(res));
|
||||
goto bail;
|
||||
}
|
||||
anyGood = false;
|
||||
@@ -520,39 +544,45 @@ bool VulkanMayBeAvailable() {
|
||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
||||
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
||||
anyGood = true;
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Eligible device found: '%s'", props.deviceName);
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Eligible device found: '%s'", props.deviceName);
|
||||
break;
|
||||
default:
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName);
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName);
|
||||
break;
|
||||
}
|
||||
// TODO: Should also check queuefamilyproperties for a GRAPHICS queue family? Oh well.
|
||||
}
|
||||
|
||||
if (!anyGood) {
|
||||
WARN_LOG(G3D, "VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!");
|
||||
WARN_LOG(Log::G3D, "VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!");
|
||||
g_vulkanMayBeAvailable = false;
|
||||
} else {
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Found working Vulkan API!");
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Found working Vulkan API!");
|
||||
g_vulkanMayBeAvailable = true;
|
||||
}
|
||||
|
||||
bail:
|
||||
g_vulkanAvailabilityChecked = true;
|
||||
if (instance) {
|
||||
INFO_LOG(G3D, "VulkanMayBeAvailable: Destroying instance");
|
||||
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Destroying instance");
|
||||
localDestroyInstance(instance, nullptr);
|
||||
}
|
||||
if (lib) {
|
||||
VulkanFreeLibrary(lib);
|
||||
}
|
||||
if (!g_vulkanMayBeAvailable) {
|
||||
WARN_LOG(G3D, "Vulkan with working device not detected.");
|
||||
WARN_LOG(Log::G3D, "Vulkan with working device not detected.");
|
||||
}
|
||||
return g_vulkanMayBeAvailable;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VulkanLoad(std::string *errorStr) {
|
||||
#if PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
INFO_LOG(Log::G3D, "iOS: Vulkan doesn't need loading");
|
||||
return true;
|
||||
#else
|
||||
|
||||
if (!vulkanLibrary) {
|
||||
vulkanLibrary = VulkanLoadLibrary(errorStr);
|
||||
if (!vulkanLibrary) {
|
||||
@@ -569,17 +599,20 @@ bool VulkanLoad(std::string *errorStr) {
|
||||
LOAD_GLOBAL_FUNC(vkEnumerateInstanceLayerProperties);
|
||||
|
||||
if (vkCreateInstance && vkGetInstanceProcAddr && vkGetDeviceProcAddr && vkEnumerateInstanceExtensionProperties && vkEnumerateInstanceLayerProperties) {
|
||||
INFO_LOG(G3D, "VulkanLoad: Base functions loaded.");
|
||||
INFO_LOG(Log::G3D, "VulkanLoad: Base functions loaded.");
|
||||
// NOTE: It's ok if vkEnumerateInstanceVersion is missing.
|
||||
return true;
|
||||
} else {
|
||||
*errorStr = "Failed to load Vulkan base functions";
|
||||
ERROR_LOG(G3D, "VulkanLoad: %s", errorStr->c_str());
|
||||
ERROR_LOG(Log::G3D, "VulkanLoad: %s", errorStr->c_str());
|
||||
VulkanFreeLibrary(vulkanLibrary);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions) {
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion) {
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
// OK, let's use the above functions to get the rest.
|
||||
LOAD_INSTANCE_FUNC(instance, vkDestroyInstance);
|
||||
LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices);
|
||||
@@ -632,8 +665,8 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &en
|
||||
LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR);
|
||||
|
||||
if (enabledExtensions.KHR_get_physical_device_properties2) {
|
||||
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR);
|
||||
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR);
|
||||
LOAD_INSTANCE_FUNC_CORE(instance, vkGetPhysicalDeviceProperties2, vkGetPhysicalDeviceProperties2KHR, VK_API_VERSION_1_1);
|
||||
LOAD_INSTANCE_FUNC_CORE(instance, vkGetPhysicalDeviceFeatures2, vkGetPhysicalDeviceFeatures2KHR, VK_API_VERSION_1_1);
|
||||
}
|
||||
|
||||
if (enabledExtensions.EXT_debug_utils) {
|
||||
@@ -646,14 +679,16 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &en
|
||||
LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectTagEXT);
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Vulkan instance functions loaded.");
|
||||
INFO_LOG(Log::G3D, "Vulkan instance functions loaded.");
|
||||
#endif
|
||||
}
|
||||
|
||||
// On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may
|
||||
// increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very
|
||||
// good for multi-device - not likely we'll ever try that anyway though.
|
||||
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions) {
|
||||
INFO_LOG(G3D, "Vulkan device functions loaded.");
|
||||
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion) {
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
INFO_LOG(Log::G3D, "Vulkan device functions loaded.");
|
||||
|
||||
LOAD_DEVICE_FUNC(device, vkQueueSubmit);
|
||||
LOAD_DEVICE_FUNC(device, vkQueueWaitIdle);
|
||||
@@ -785,16 +820,19 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE
|
||||
LOAD_DEVICE_FUNC(device, vkGetRefreshCycleDurationGOOGLE);
|
||||
}
|
||||
if (enabledExtensions.KHR_dedicated_allocation) {
|
||||
LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR);
|
||||
LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR);
|
||||
LOAD_DEVICE_FUNC_CORE(device, vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR, VK_API_VERSION_1_1);
|
||||
LOAD_DEVICE_FUNC_CORE(device, vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR, VK_API_VERSION_1_1);
|
||||
}
|
||||
if (enabledExtensions.KHR_create_renderpass2) {
|
||||
LOAD_DEVICE_FUNC(device, vkCreateRenderPass2KHR);
|
||||
LOAD_DEVICE_FUNC_CORE(device, vkCreateRenderPass2, vkCreateRenderPass2KHR, VK_API_VERSION_1_2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanFree() {
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
VulkanFreeLibrary(vulkanLibrary);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *VulkanResultToString(VkResult res) {
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||
#elif defined(_WIN32)
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
@@ -29,7 +31,10 @@
|
||||
#define VK_USE_PLATFORM_METAL_EXT
|
||||
#endif
|
||||
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VK_ENABLE_BETA_EXTENSIONS 1 // VK_KHR_portability_subset
|
||||
#endif
|
||||
|
||||
#include "ext/vulkan/vulkan.h"
|
||||
#include <string>
|
||||
@@ -40,6 +45,7 @@
|
||||
#endif
|
||||
|
||||
namespace PPSSPP_VK {
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
// Putting our own Vulkan function pointers in a namespace ensures that ppsspp_libretro.so doesn't collide with libvulkan.so.
|
||||
extern PFN_vkCreateInstance vkCreateInstance;
|
||||
extern PFN_vkDestroyInstance vkDestroyInstance;
|
||||
@@ -230,15 +236,17 @@ extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
|
||||
extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
|
||||
|
||||
// Assorted other extensions.
|
||||
extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
|
||||
extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
||||
extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2;
|
||||
extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2;
|
||||
extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
|
||||
extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
|
||||
extern PFN_vkCreateRenderPass2 vkCreateRenderPass2;
|
||||
|
||||
extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT;
|
||||
extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
|
||||
extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
|
||||
extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR;
|
||||
extern PFN_vkWaitForPresentKHR vkWaitForPresentKHR;
|
||||
extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE;
|
||||
extern PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE;
|
||||
#endif // !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
} // namespace PPSSPP_VK
|
||||
|
||||
// For fast extension-enabled checks.
|
||||
@@ -260,6 +268,7 @@ struct VulkanExtensions {
|
||||
bool KHR_present_id; // Should probably check the feature flags instead.
|
||||
bool KHR_present_wait; // Same
|
||||
bool GOOGLE_display_timing;
|
||||
bool EXT_provoking_vertex;
|
||||
// bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers.
|
||||
};
|
||||
|
||||
@@ -268,8 +277,8 @@ bool VulkanMayBeAvailable();
|
||||
void VulkanSetAvailable(bool available);
|
||||
|
||||
bool VulkanLoad(std::string *errorStr);
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions);
|
||||
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions);
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion);
|
||||
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion);
|
||||
void VulkanFree();
|
||||
|
||||
const char *VulkanResultToString(VkResult res);
|
||||
@@ -121,7 +121,7 @@ void VulkanPushPool::BeginFrame() {
|
||||
size_t size = blocks_.back().size;
|
||||
blocks_.back().Destroy(vulkan_);
|
||||
blocks_.pop_back();
|
||||
DEBUG_LOG(G3D, "%s: Garbage collected block of size %s in %0.2f ms", name_, NiceSizeFormat(size).c_str(), time_now_d() - start);
|
||||
DEBUG_LOG(Log::G3D, "%s: Garbage collected block of size %s in %0.2f ms", name_, NiceSizeFormat(size).c_str(), time_now_d() - start);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ void VulkanPushPool::NextBlock(VkDeviceSize allocationSize) {
|
||||
blocks_.back().used = allocationSize;
|
||||
blocks_.back().lastUsed = time_now_d();
|
||||
// curBlockIndex_ is already set correctly here.
|
||||
DEBUG_LOG(G3D, "%s: Created new block of size %s in %0.2f ms", name_, NiceSizeFormat(newBlockSize).c_str(), 1000.0 * (time_now_d() - start));
|
||||
DEBUG_LOG(Log::G3D, "%s: Created new block of size %s in %0.2f ms", name_, NiceSizeFormat(newBlockSize).c_str(), 1000.0 * (time_now_d() - start));
|
||||
}
|
||||
|
||||
size_t VulkanPushPool::GetUsedThisFrame() const {
|
||||
|
||||
@@ -50,13 +50,13 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm
|
||||
static const char * const indent[4] = { "", " ", " ", " " };
|
||||
|
||||
if (!scopes_.empty()) {
|
||||
INFO_LOG(G3D, "Profiling events this frame:");
|
||||
INFO_LOG(Log::G3D, "Profiling events this frame:");
|
||||
}
|
||||
|
||||
// Log it all out.
|
||||
for (auto &scope : scopes_) {
|
||||
if (scope.endQueryId == -1) {
|
||||
WARN_LOG(G3D, "Unclosed scope: %s", scope.name);
|
||||
WARN_LOG(Log::G3D, "Unclosed scope: %s", scope.name);
|
||||
continue;
|
||||
}
|
||||
uint64_t startTime = results[scope.startQueryId];
|
||||
@@ -66,7 +66,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, milliseconds);
|
||||
INFO_LOG(Log::G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds);
|
||||
}
|
||||
|
||||
scopes_.clear();
|
||||
|
||||
@@ -20,11 +20,11 @@ static void MergeRenderAreaRectInto(VkRect2D *dest, const VkRect2D &src) {
|
||||
dest->extent.height += (dest->offset.y - src.offset.y);
|
||||
dest->offset.y = src.offset.y;
|
||||
}
|
||||
if (dest->extent.width < src.extent.width) {
|
||||
dest->extent.width = src.extent.width;
|
||||
if (dest->offset.x + dest->extent.width < src.offset.x + src.extent.width) {
|
||||
dest->extent.width = src.offset.x + src.extent.width - dest->offset.x;
|
||||
}
|
||||
if (dest->extent.height < src.extent.height) {
|
||||
dest->extent.height = src.extent.height;
|
||||
if (dest->offset.y + dest->extent.height < src.offset.y + src.extent.height) {
|
||||
dest->extent.height = src.offset.y + src.extent.height - dest->offset.y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ RenderPassType MergeRPTypes(RenderPassType a, RenderPassType b) {
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::CreateDeviceObjects() {
|
||||
INFO_LOG(G3D, "VulkanQueueRunner::CreateDeviceObjects");
|
||||
INFO_LOG(Log::G3D, "VulkanQueueRunner::CreateDeviceObjects");
|
||||
|
||||
RPKey key{
|
||||
VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR,
|
||||
@@ -56,19 +56,19 @@ void VulkanQueueRunner::CreateDeviceObjects() {
|
||||
// Just to check whether it makes sense to split some of these. drawidx is way bigger than the others...
|
||||
// We should probably just move to variable-size data in a raw buffer anyway...
|
||||
VkRenderData rd;
|
||||
INFO_LOG(G3D, "sizeof(pipeline): %d", (int)sizeof(rd.pipeline));
|
||||
INFO_LOG(G3D, "sizeof(draw): %d", (int)sizeof(rd.draw));
|
||||
INFO_LOG(G3D, "sizeof(drawidx): %d", (int)sizeof(rd.drawIndexed));
|
||||
INFO_LOG(G3D, "sizeof(clear): %d", (int)sizeof(rd.clear));
|
||||
INFO_LOG(G3D, "sizeof(viewport): %d", (int)sizeof(rd.viewport));
|
||||
INFO_LOG(G3D, "sizeof(scissor): %d", (int)sizeof(rd.scissor));
|
||||
INFO_LOG(G3D, "sizeof(blendColor): %d", (int)sizeof(rd.blendColor));
|
||||
INFO_LOG(G3D, "sizeof(push): %d", (int)sizeof(rd.push));
|
||||
INFO_LOG(Log::G3D, "sizeof(pipeline): %d", (int)sizeof(rd.pipeline));
|
||||
INFO_LOG(Log::G3D, "sizeof(draw): %d", (int)sizeof(rd.draw));
|
||||
INFO_LOG(Log::G3D, "sizeof(drawidx): %d", (int)sizeof(rd.drawIndexed));
|
||||
INFO_LOG(Log::G3D, "sizeof(clear): %d", (int)sizeof(rd.clear));
|
||||
INFO_LOG(Log::G3D, "sizeof(viewport): %d", (int)sizeof(rd.viewport));
|
||||
INFO_LOG(Log::G3D, "sizeof(scissor): %d", (int)sizeof(rd.scissor));
|
||||
INFO_LOG(Log::G3D, "sizeof(blendColor): %d", (int)sizeof(rd.blendColor));
|
||||
INFO_LOG(Log::G3D, "sizeof(push): %d", (int)sizeof(rd.push));
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::DestroyDeviceObjects() {
|
||||
INFO_LOG(G3D, "VulkanQueueRunner::DestroyDeviceObjects");
|
||||
INFO_LOG(Log::G3D, "VulkanQueueRunner::DestroyDeviceObjects");
|
||||
|
||||
syncReadback_.Destroy(vulkan_);
|
||||
|
||||
@@ -87,7 +87,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit, VulkanBarrierBa
|
||||
VkImage *swapchainImages = new VkImage[swapchainImageCount_];
|
||||
res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "vkGetSwapchainImagesKHR failed");
|
||||
ERROR_LOG(Log::G3D, "vkGetSwapchainImagesKHR failed");
|
||||
delete[] swapchainImages;
|
||||
return false;
|
||||
}
|
||||
@@ -245,10 +245,9 @@ void VulkanQueueRunner::DestroyBackBuffers() {
|
||||
}
|
||||
framebuffers_.clear();
|
||||
|
||||
INFO_LOG(G3D, "Backbuffers destroyed");
|
||||
INFO_LOG(Log::G3D, "Backbuffers destroyed");
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
VKRRenderPass *VulkanQueueRunner::GetRenderPass(const RPKey &key) {
|
||||
@@ -489,18 +488,24 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
|
||||
for (int j = 0; j < (int)copies.size(); j++) {
|
||||
steps[i + j] = copies[j];
|
||||
}
|
||||
|
||||
const int firstRender = i + (int)copies.size();
|
||||
|
||||
// Write the renders back (so they will be deleted properly).
|
||||
for (int j = 0; j < (int)renders.size(); j++) {
|
||||
steps[i + j + copies.size()] = renders[j];
|
||||
steps[firstRender + j] = renders[j];
|
||||
}
|
||||
_assert_(steps[i + copies.size()]->stepType == VKRStepType::RENDER);
|
||||
_assert_(steps[firstRender]->stepType == VKRStepType::RENDER);
|
||||
// Combine the renders.
|
||||
for (int j = 1; j < (int)renders.size(); j++) {
|
||||
steps[i + copies.size()]->commands.reserve(renders[j]->commands.size());
|
||||
steps[firstRender]->commands.reserve(renders[j]->commands.size());
|
||||
for (int k = 0; k < (int)renders[j]->commands.size(); k++) {
|
||||
steps[i + copies.size()]->commands.push_back(renders[j]->commands[k]);
|
||||
steps[firstRender]->commands.push_back(renders[j]->commands[k]);
|
||||
}
|
||||
steps[i + copies.size() + j]->stepType = VKRStepType::RENDER_SKIP;
|
||||
MergeRenderAreaRectInto(&steps[firstRender]->render.renderArea, renders[j]->render.renderArea);
|
||||
// Easier than removing them from the list, though that might be the better option.
|
||||
steps[firstRender + j]->stepType = VKRStepType::RENDER_SKIP;
|
||||
steps[firstRender + j]->commands.clear();
|
||||
}
|
||||
// We're done.
|
||||
break;
|
||||
@@ -561,6 +566,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
MergeRenderAreaRectInto(&steps[i]->render.renderArea, steps[j]->render.renderArea);
|
||||
steps[j]->stepType = VKRStepType::RENDER_SKIP;
|
||||
}
|
||||
|
||||
@@ -576,6 +582,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
MergeRenderAreaRectInto(&steps[i + 1]->render.renderArea, steps[j]->render.renderArea);
|
||||
steps[j]->stepType = VKRStepType::RENDER_SKIP;
|
||||
}
|
||||
|
||||
@@ -657,7 +664,8 @@ void VulkanQueueRunner::ApplySonicHack(std::vector<VKRStep *> &steps) {
|
||||
for (int k = 0; k < (int)type2[j]->commands.size(); k++) {
|
||||
steps[i + type1.size()]->commands.push_back(type2[j]->commands[k]);
|
||||
}
|
||||
steps[i + j + type1.size()]->stepType = VKRStepType::RENDER_SKIP;
|
||||
// Technically, should merge render area here, but they're all the same so not needed.
|
||||
steps[i + type1.size() + j]->stepType = VKRStepType::RENDER_SKIP;
|
||||
}
|
||||
// We're done.
|
||||
break;
|
||||
@@ -803,7 +811,7 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector<VKRStep *> &steps) {
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps, bool verbose) {
|
||||
INFO_LOG(G3D, "=================== FRAME ====================");
|
||||
INFO_LOG(Log::G3D, "=================== FRAME ====================");
|
||||
for (size_t i = 0; i < steps.size(); i++) {
|
||||
const VKRStep &step = *steps[i];
|
||||
switch (step.stepType) {
|
||||
@@ -823,11 +831,11 @@ void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps, bool verbo
|
||||
LogReadbackImage(step);
|
||||
break;
|
||||
case VKRStepType::RENDER_SKIP:
|
||||
INFO_LOG(G3D, "(skipped render pass)");
|
||||
INFO_LOG(Log::G3D, "(skipped render pass)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
INFO_LOG(G3D, "------------------- SUBMIT ------------------");
|
||||
INFO_LOG(Log::G3D, "------------------- SUBMIT ------------------");
|
||||
}
|
||||
|
||||
const char *RenderPassActionName(VKRRenderPassLoadAction a) {
|
||||
@@ -862,47 +870,47 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) {
|
||||
int w = r.framebuffer ? r.framebuffer->width : vulkan_->GetBackbufferWidth();
|
||||
int h = r.framebuffer ? r.framebuffer->height : vulkan_->GetBackbufferHeight();
|
||||
|
||||
INFO_LOG(G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.colorLoad), RenderPassActionName(r.depthLoad), RenderPassActionName(r.stencilLoad));
|
||||
INFO_LOG(Log::G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.colorLoad), RenderPassActionName(r.depthLoad), RenderPassActionName(r.stencilLoad));
|
||||
// TODO: Log these in detail.
|
||||
for (int i = 0; i < (int)pass.preTransitions.size(); i++) {
|
||||
INFO_LOG(G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->Tag(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout));
|
||||
INFO_LOG(Log::G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->Tag(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout));
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
for (auto &cmd : pass.commands) {
|
||||
switch (cmd.cmd) {
|
||||
case VKRRenderCommand::REMOVED:
|
||||
INFO_LOG(G3D, " (Removed)");
|
||||
INFO_LOG(Log::G3D, " (Removed)");
|
||||
break;
|
||||
case VKRRenderCommand::BIND_GRAPHICS_PIPELINE:
|
||||
INFO_LOG(G3D, " BindGraphicsPipeline(%x)", (int)(intptr_t)cmd.graphics_pipeline.pipeline);
|
||||
INFO_LOG(Log::G3D, " BindGraphicsPipeline(%x)", (int)(intptr_t)cmd.graphics_pipeline.pipeline);
|
||||
break;
|
||||
case VKRRenderCommand::BLEND:
|
||||
INFO_LOG(G3D, " BlendColor(%08x)", cmd.blendColor.color);
|
||||
INFO_LOG(Log::G3D, " BlendColor(%08x)", cmd.blendColor.color);
|
||||
break;
|
||||
case VKRRenderCommand::CLEAR:
|
||||
INFO_LOG(G3D, " Clear");
|
||||
INFO_LOG(Log::G3D, " Clear");
|
||||
break;
|
||||
case VKRRenderCommand::DRAW:
|
||||
INFO_LOG(G3D, " Draw(%d)", cmd.draw.count);
|
||||
INFO_LOG(Log::G3D, " Draw(%d)", cmd.draw.count);
|
||||
break;
|
||||
case VKRRenderCommand::DRAW_INDEXED:
|
||||
INFO_LOG(G3D, " DrawIndexed(%d)", cmd.drawIndexed.count);
|
||||
INFO_LOG(Log::G3D, " DrawIndexed(%d)", cmd.drawIndexed.count);
|
||||
break;
|
||||
case VKRRenderCommand::SCISSOR:
|
||||
INFO_LOG(G3D, " Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height);
|
||||
INFO_LOG(Log::G3D, " Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height);
|
||||
break;
|
||||
case VKRRenderCommand::STENCIL:
|
||||
INFO_LOG(G3D, " Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask);
|
||||
INFO_LOG(Log::G3D, " Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask);
|
||||
break;
|
||||
case VKRRenderCommand::VIEWPORT:
|
||||
INFO_LOG(G3D, " Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth);
|
||||
INFO_LOG(Log::G3D, " Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth);
|
||||
break;
|
||||
case VKRRenderCommand::PUSH_CONSTANTS:
|
||||
INFO_LOG(G3D, " PushConstants(%d)", cmd.push.size);
|
||||
INFO_LOG(Log::G3D, " PushConstants(%d)", cmd.push.size);
|
||||
break;
|
||||
case VKRRenderCommand::DEBUG_ANNOTATION:
|
||||
INFO_LOG(G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation);
|
||||
INFO_LOG(Log::G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation);
|
||||
break;
|
||||
|
||||
case VKRRenderCommand::NUM_RENDER_COMMANDS:
|
||||
@@ -911,221 +919,39 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) {
|
||||
}
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, " Final: %s %s", ImageLayoutToString(pass.render.finalColorLayout), ImageLayoutToString(pass.render.finalDepthStencilLayout));
|
||||
INFO_LOG(G3D, "RENDER End(%s) - %d commands executed", framebuf, (int)pass.commands.size());
|
||||
INFO_LOG(Log::G3D, " Final: %s %s", ImageLayoutToString(pass.render.finalColorLayout), ImageLayoutToString(pass.render.finalDepthStencilLayout));
|
||||
INFO_LOG(Log::G3D, "RENDER End(%s) - %d commands executed", framebuf, (int)pass.commands.size());
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogCopy(const VKRStep &step) {
|
||||
INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogBlit(const VKRStep &step) {
|
||||
INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogReadback(const VKRStep &step) {
|
||||
INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) {
|
||||
INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
}
|
||||
|
||||
void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout, int numLayers, VulkanBarrierBatch *recordBarrier) {
|
||||
if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
VkPipelineStageFlags srcStageMask = 0;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
switch (colorLayout) {
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
// No need to specify stage or access.
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
// Already the right color layout. Unclear that we need to do a lot here..
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
// We came from the Mali workaround, and are transitioning back to COLOR_ATTACHMENT_OPTIMAL.
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "TransitionToOptimal: Unexpected color layout %d", (int)colorLayout);
|
||||
break;
|
||||
}
|
||||
recordBarrier->TransitionImage(
|
||||
colorImage, 0, 1, numLayers, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
colorLayout,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
srcAccessMask,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
srcStageMask,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
}
|
||||
|
||||
if (depthStencilImage != VK_NULL_HANDLE && depthStencilLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
VkPipelineStageFlags srcStageMask = 0;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
switch (depthStencilLayout) {
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
// No need to specify stage or access.
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
// Already the right depth layout. Unclear that we need to do a lot here..
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "TransitionToOptimal: Unexpected depth layout %d", (int)depthStencilLayout);
|
||||
break;
|
||||
}
|
||||
recordBarrier->TransitionImage(
|
||||
depthStencilImage, 0, 1, numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||
depthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
srcAccessMask,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
||||
srcStageMask,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, int numLayers, VkImageLayout depthStencilLayout) {
|
||||
VkPipelineStageFlags srcStageMask = 0;
|
||||
VkPipelineStageFlags dstStageMask = 0;
|
||||
|
||||
// If layouts aren't optimal, transition them.
|
||||
VkImageMemoryBarrier barrier[2]{};
|
||||
|
||||
int barrierCount = 0;
|
||||
if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier[0].pNext = nullptr;
|
||||
srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
barrier[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
// And the final transition.
|
||||
// Don't need to transition it if VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL.
|
||||
switch (colorLayout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
// Nothing to do.
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "TransitionFromOptimal: Unexpected final color layout %d", (int)colorLayout);
|
||||
break;
|
||||
}
|
||||
barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
barrier[0].newLayout = colorLayout;
|
||||
barrier[0].image = colorImage;
|
||||
barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier[0].subresourceRange.baseMipLevel = 0;
|
||||
barrier[0].subresourceRange.levelCount = 1;
|
||||
barrier[0].subresourceRange.layerCount = numLayers;
|
||||
barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrierCount++;
|
||||
}
|
||||
|
||||
if (depthStencilImage && depthStencilLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
barrier[barrierCount].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier[barrierCount].pNext = nullptr;
|
||||
|
||||
srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
barrier[barrierCount].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
switch (depthStencilLayout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
barrier[barrierCount].dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
barrier[barrierCount].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
barrier[barrierCount].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
// Nothing to do.
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "TransitionFromOptimal: Unexpected final depth layout %d", (int)depthStencilLayout);
|
||||
break;
|
||||
}
|
||||
barrier[barrierCount].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
barrier[barrierCount].newLayout = depthStencilLayout;
|
||||
barrier[barrierCount].image = depthStencilImage;
|
||||
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 = numLayers;
|
||||
barrier[barrierCount].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier[barrierCount].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrierCount++;
|
||||
}
|
||||
if (barrierCount) {
|
||||
vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, barrierCount, barrier);
|
||||
}
|
||||
INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd, int curFrame, QueueProfileContext &profile) {
|
||||
for (size_t i = 0; i < step.preTransitions.size(); i++) {
|
||||
const TransitionRequest &iter = step.preTransitions[i];
|
||||
if (iter.aspect == VK_IMAGE_ASPECT_COLOR_BIT && iter.fb->color.layout != iter.targetLayout) {
|
||||
recordBarrier_.TransitionImageAuto(
|
||||
iter.fb->color.image,
|
||||
0,
|
||||
1,
|
||||
iter.fb->numLayers,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
iter.fb->color.layout,
|
||||
recordBarrier_.TransitionColorImageAuto(
|
||||
&iter.fb->color,
|
||||
iter.targetLayout
|
||||
);
|
||||
iter.fb->color.layout = iter.targetLayout;
|
||||
} else if (iter.fb->depth.image != VK_NULL_HANDLE && (iter.aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) && iter.fb->depth.layout != iter.targetLayout) {
|
||||
recordBarrier_.TransitionImageAuto(
|
||||
iter.fb->depth.image,
|
||||
0,
|
||||
1,
|
||||
iter.fb->numLayers,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||
iter.fb->depth.layout,
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(
|
||||
&iter.fb->depth,
|
||||
iter.targetLayout
|
||||
);
|
||||
iter.fb->depth.layout = iter.targetLayout;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1140,7 +966,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
}
|
||||
|
||||
// Write-after-write hazards. Fixed flicker in God of War on ARM (before we added another fix that removed these).
|
||||
// These aren't so common so not bothering to combine the barrier with the pretransition one.
|
||||
// NOTE: These are commented out because the normal barriers no longer check for equality, effectively generating these
|
||||
// barriers automatically. This is safe, but sometimes I think can be improved on.
|
||||
/*
|
||||
if (step.render.framebuffer) {
|
||||
int n = 0;
|
||||
int stage = 0;
|
||||
@@ -1158,7 +986,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
|
||||
);
|
||||
);
|
||||
}
|
||||
if (step.render.framebuffer->depth.image != VK_NULL_HANDLE && step.render.framebuffer->depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
recordBarrier_.TransitionImage(
|
||||
@@ -1171,16 +999,16 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||
);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// This reads the layout of the color and depth images, and chooses a render pass using them that
|
||||
// will transition to the desired final layout.
|
||||
// This chooses a render pass according to the load/store attachment state. We no longer transition
|
||||
// image layouts as part of the passes.
|
||||
//
|
||||
// NOTE: Flushes recordBarrier_.
|
||||
// NOTE: Unconditionally flushes recordBarrier_.
|
||||
VKRRenderPass *renderPass = PerformBindFramebufferAsRenderTarget(step, cmd);
|
||||
|
||||
int curWidth = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth();
|
||||
@@ -1395,18 +1223,22 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(G3D, "Unimpl queue command");
|
||||
ERROR_LOG(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, fb->numLayers, step.render.finalDepthStencilLayout);
|
||||
_dbg_assert_(recordBarrier_.empty());
|
||||
|
||||
fb->color.layout = step.render.finalColorLayout;
|
||||
fb->depth.layout = step.render.finalDepthStencilLayout;
|
||||
if (fb) {
|
||||
// If the desired final layout aren't the optimal layout needed next, early-transition the image.
|
||||
if (step.render.finalColorLayout != fb->color.layout) {
|
||||
recordBarrier_.TransitionColorImageAuto(&fb->color, step.render.finalColorLayout);
|
||||
}
|
||||
if (fb->depth.image && step.render.finalDepthStencilLayout != fb->depth.layout) {
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(&fb->depth, step.render.finalDepthStencilLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1422,6 +1254,9 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR
|
||||
|
||||
VkSampleCountFlagBits sampleCount;
|
||||
|
||||
// Can be used to separate the final*Layout barrier from the rest for debugging in renderdoc.
|
||||
// recordBarrier_.Flush(cmd);
|
||||
|
||||
if (step.render.framebuffer) {
|
||||
_dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
_dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
@@ -1447,6 +1282,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR
|
||||
step.render.colorLoad == VKRRenderPassLoadAction::CLEAR &&
|
||||
vulkan_->GetPhysicalDeviceProperties().properties.driverVersion == 0xaa9c4b29;
|
||||
if (maliBugWorkaround) {
|
||||
// A little suboptimal but let's go for maximum safety here.
|
||||
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,
|
||||
@@ -1455,7 +1291,12 @@ 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, fb->numLayers, &recordBarrier_);
|
||||
recordBarrier_.TransitionColorImageAuto(&fb->color, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
// If the render pass doesn't touch depth, we can avoid a layout transition of the depth buffer.
|
||||
if (fb->depth.image && RenderPassTypeHasDepth(step.render.renderPassType)) {
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(&fb->depth, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
|
||||
// The transition from the optimal format happens after EndRenderPass, now that we don't
|
||||
// do it as part of the renderpass itself anymore.
|
||||
@@ -1539,45 +1380,38 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
// 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) {
|
||||
SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_);
|
||||
SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_);
|
||||
recordBarrier_.TransitionColorImageAuto(&src->color, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
recordBarrier_.TransitionColorImageAuto(&dst->color, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_);
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(&src->depth, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
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);
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(&dst->depth, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
} else {
|
||||
// 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);
|
||||
recordBarrier_.TransitionColorImageAuto(&src->msaaColor, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
recordBarrier_.TransitionColorImageAuto(&dst->msaaColor, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
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_.TransitionDepthStencilImageAuto(&src->msaaDepth, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(&dst->msaaDepth, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1635,6 +1469,7 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
|
||||
);
|
||||
src->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
recordBarrier_.TransitionImage(
|
||||
dst->msaaColor.image,
|
||||
0,
|
||||
@@ -1648,7 +1483,6 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
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)) {
|
||||
@@ -1665,6 +1499,7 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
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;
|
||||
recordBarrier_.TransitionImage(
|
||||
dst->msaaDepth.image,
|
||||
0,
|
||||
@@ -1678,9 +1513,9 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
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;
|
||||
}
|
||||
// Probably not necessary.
|
||||
recordBarrier_.Flush(cmd);
|
||||
}
|
||||
}
|
||||
@@ -1697,16 +1532,16 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
|
||||
// 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_);
|
||||
recordBarrier_.TransitionColorImageAuto(&src->color, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
recordBarrier_.TransitionColorImageAuto(&dst->color, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
|
||||
// We can't copy only depth or only stencil unfortunately.
|
||||
if (step.blit.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
_assert_(src->depth.image != VK_NULL_HANDLE);
|
||||
_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_.TransitionDepthStencilImageAuto(&src->depth, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(&dst->depth, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
|
||||
recordBarrier_.Flush(cmd);
|
||||
@@ -1754,111 +1589,6 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier) {
|
||||
if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
||||
return;
|
||||
}
|
||||
VkImageAspectFlags imageAspect = aspect;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
VkPipelineStageFlags srcStageMask = 0;
|
||||
switch (img.layout) {
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "Transition from this layout to transfer src not supported (%d)", (int)img.layout);
|
||||
break;
|
||||
}
|
||||
|
||||
if (img.format == VK_FORMAT_D16_UNORM_S8_UINT || img.format == VK_FORMAT_D24_UNORM_S8_UINT || img.format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
// Barrier must specify both for combined depth/stencil buffers.
|
||||
imageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
} else {
|
||||
imageAspect = aspect;
|
||||
}
|
||||
|
||||
recordBarrier->TransitionImage(
|
||||
img.image,
|
||||
0,
|
||||
1,
|
||||
img.numLayers,
|
||||
imageAspect,
|
||||
img.layout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
srcAccessMask,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
srcStageMask,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
);
|
||||
img.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier) {
|
||||
if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
return;
|
||||
}
|
||||
VkImageAspectFlags imageAspect = aspect;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
VkPipelineStageFlags srcStageMask = 0;
|
||||
if (img.format == VK_FORMAT_D16_UNORM_S8_UINT || img.format == VK_FORMAT_D24_UNORM_S8_UINT || img.format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
// Barrier must specify both for combined depth/stencil buffers.
|
||||
imageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
} else {
|
||||
imageAspect = aspect;
|
||||
}
|
||||
|
||||
switch (img.layout) {
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "Transition from this layout to transfer dst not supported (%d)", (int)img.layout);
|
||||
break;
|
||||
}
|
||||
|
||||
recordBarrier->TransitionImage(
|
||||
img.image,
|
||||
0,
|
||||
1,
|
||||
img.numLayers,
|
||||
aspect,
|
||||
img.layout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
srcAccessMask,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
srcStageMask,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
);
|
||||
|
||||
img.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier) {
|
||||
VkImageAspectFlags imageAspect = aspect;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
@@ -1923,32 +1653,31 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
||||
// 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.
|
||||
// Regarding layers, backbuffer currently only has one layer.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
recordBarrier_.TransitionImage(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);
|
||||
0, VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
copyLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
image = backbufferImage_;
|
||||
} else {
|
||||
VKRImage *srcImage;
|
||||
if (step.readback.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
srcImage = &step.readback.src->color;
|
||||
recordBarrier_.TransitionColorImageAuto(srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
} else if (step.readback.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
srcImage = &step.readback.src->depth;
|
||||
recordBarrier_.TransitionDepthStencilImageAuto(srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
_dbg_assert_(srcImage->image != VK_NULL_HANDLE);
|
||||
} else {
|
||||
_dbg_assert_msg_(false, "No image aspect to readback?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcImage->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
||||
SetupTransitionToTransferSrc(*srcImage, step.readback.aspectMask, &recordBarrier_);
|
||||
recordBarrier_.Flush(cmd);
|
||||
}
|
||||
image = srcImage->image;
|
||||
copyLayout = srcImage->layout;
|
||||
}
|
||||
|
||||
recordBarrier_.Flush(cmd);
|
||||
|
||||
// TODO: Handle different readback formats!
|
||||
u32 readbackSizeInBytes = sizeof(uint32_t) * step.readback.srcRect.extent.width * step.readback.srcRect.extent.height;
|
||||
|
||||
@@ -1990,22 +1719,19 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
||||
// 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.
|
||||
// Regarding layers, backbuffer currently only has one layer.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
recordBarrier_.TransitionImage(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);
|
||||
VK_ACCESS_TRANSFER_READ_BIT, 0,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||
recordBarrier_.Flush(cmd); // probably not needed
|
||||
copyLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
// TODO: Clean this up - just reusing `SetupTransitionToTransferSrc`.
|
||||
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_);
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
recordBarrier_.TransitionColorImageAuto(step.readback_image.image, &layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 1, 1);
|
||||
recordBarrier_.Flush(cmd);
|
||||
|
||||
ResizeReadbackBuffer(&syncReadback_, sizeof(uint32_t) * step.readback_image.srcRect.extent.width * step.readback_image.srcRect.extent.height);
|
||||
@@ -2022,11 +1748,12 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe
|
||||
vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, syncReadback_.buffer, 1, ®ion);
|
||||
|
||||
// Now transfer it back to a texture.
|
||||
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..
|
||||
recordBarrier_.TransitionImage(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,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
recordBarrier_.Flush(cmd); // probably not needed
|
||||
|
||||
// NOTE: Can't read the buffer using the CPU here - need to sync first.
|
||||
// Doing that will also act like a heavyweight barrier ensuring that device writes are visible on the host.
|
||||
@@ -2059,7 +1786,7 @@ bool VulkanQueueRunner::CopyReadbackBuffer(FrameData &frameData, VKRFramebuffer
|
||||
VkResult res = vmaMapMemory(vulkan_->Allocator(), readback->allocation, &mappedData);
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res);
|
||||
ERROR_LOG(Log::G3D, "CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2087,7 +1814,7 @@ bool VulkanQueueRunner::CopyReadbackBuffer(FrameData &frameData, VKRFramebuffer
|
||||
ConvertToD16(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, srcFormat);
|
||||
} else {
|
||||
// TODO: Maybe a depth conversion or something?
|
||||
ERROR_LOG(G3D, "CopyReadbackBuffer: Unknown format");
|
||||
ERROR_LOG(Log::G3D, "CopyReadbackBuffer: Unknown format");
|
||||
_assert_msg_(false, "CopyReadbackBuffer: Unknown src format %d", (int)srcFormat);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ enum class PipelineFlags : u8 {
|
||||
USES_GEOMETRY_SHADER = (1 << 3),
|
||||
USES_MULTIVIEW = (1 << 4), // Inherited from the render pass it was created with.
|
||||
USES_DISCARD = (1 << 5),
|
||||
USES_FLAT_SHADING = (1 << 6),
|
||||
};
|
||||
ENUM_CLASS_BITOPS(PipelineFlags);
|
||||
|
||||
@@ -154,9 +155,9 @@ struct VKRStep {
|
||||
VKRRenderPassStoreAction colorStore;
|
||||
VKRRenderPassStoreAction depthStore;
|
||||
VKRRenderPassStoreAction stencilStore;
|
||||
u8 clearStencil;
|
||||
uint32_t clearColor;
|
||||
float clearDepth;
|
||||
u8 clearStencil;
|
||||
int numDraws;
|
||||
// Downloads and textures from this pass.
|
||||
int numReads;
|
||||
@@ -173,20 +174,20 @@ struct VKRStep {
|
||||
VKRFramebuffer *dst;
|
||||
VkRect2D srcRect;
|
||||
VkOffset2D dstPos;
|
||||
int aspectMask;
|
||||
VkImageAspectFlags aspectMask;
|
||||
} copy;
|
||||
struct {
|
||||
VKRFramebuffer *src;
|
||||
VKRFramebuffer *dst;
|
||||
VkRect2D srcRect;
|
||||
VkRect2D dstRect;
|
||||
int aspectMask;
|
||||
VkImageAspectFlags aspectMask;
|
||||
VkFilter filter;
|
||||
} blit;
|
||||
struct {
|
||||
int aspectMask;
|
||||
VKRFramebuffer *src;
|
||||
VkRect2D srcRect;
|
||||
VkImageAspectFlags aspectMask;
|
||||
bool delayed;
|
||||
} readback;
|
||||
struct {
|
||||
@@ -289,8 +290,6 @@ private:
|
||||
void ApplySonicHack(std::vector<VKRStep *> &steps);
|
||||
void ApplyRenderPassMerge(std::vector<VKRStep *> &steps);
|
||||
|
||||
static void SetupTransitionToTransferSrc(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier);
|
||||
static void SetupTransitionToTransferDst(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier);
|
||||
static void SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier);
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "Common/VR/PPSSPPVR.h"
|
||||
|
||||
#if 0 // def _DEBUG
|
||||
#define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__)
|
||||
#define VLOG(...) NOTICE_LOG(Log::G3D, __VA_ARGS__)
|
||||
#else
|
||||
#define VLOG(...)
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
|
||||
// Sanity check.
|
||||
// Seen in crash reports from PowerVR GE8320, presumably we failed creating some shader modules.
|
||||
if (!desc->vertexShader || !desc->fragmentShader) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline - missing vs/fs shader module pointers!");
|
||||
ERROR_LOG(Log::G3D, "Failed creating graphics pipeline - missing vs/fs shader module pointers!");
|
||||
pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE);
|
||||
return false;
|
||||
}
|
||||
@@ -57,13 +57,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
|
||||
VkShaderModule gs = desc->geometryShader ? desc->geometryShader->BlockUntilReady() : VK_NULL_HANDLE;
|
||||
|
||||
if (!vs || !fs || (!gs && desc->geometryShader)) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline - missing shader modules");
|
||||
ERROR_LOG(Log::G3D, "Failed creating graphics pipeline - missing shader modules");
|
||||
pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compatibleRenderPass) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline - compatible render pass was nullptr");
|
||||
ERROR_LOG(Log::G3D, "Failed creating graphics pipeline - compatible render pass was nullptr");
|
||||
pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE);
|
||||
return false;
|
||||
}
|
||||
@@ -130,10 +130,10 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
|
||||
double taken_ms = (now - start) * 1000.0;
|
||||
|
||||
if (taken_ms < 0.1) {
|
||||
DEBUG_LOG(G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling (fast) rpType: %04x sampleBits: %d (%s)",
|
||||
DEBUG_LOG(Log::G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling (fast) rpType: %04x sampleBits: %d (%s)",
|
||||
countToCompile, GetCurrentThreadName(), taken_ms, taken_ms_since_scheduling, (u32)rpType, (u32)sampleCount, tag_.c_str());
|
||||
} else {
|
||||
INFO_LOG(G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling rpType: %04x sampleBits: %d (%s)",
|
||||
INFO_LOG(Log::G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling rpType: %04x sampleBits: %d (%s)",
|
||||
countToCompile, GetCurrentThreadName(), taken_ms, taken_ms_since_scheduling, (u32)rpType, (u32)sampleCount, tag_.c_str());
|
||||
}
|
||||
|
||||
@@ -144,12 +144,12 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
|
||||
//
|
||||
// At least create a null placeholder to avoid creating over and over if something is broken.
|
||||
pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE);
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline! VK_INCOMPLETE");
|
||||
ERROR_LOG(Log::G3D, "Failed creating graphics pipeline! VK_INCOMPLETE");
|
||||
LogCreationFailure();
|
||||
success = false;
|
||||
} else if (result != VK_SUCCESS) {
|
||||
pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE);
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
ERROR_LOG(Log::G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
LogCreationFailure();
|
||||
success = false;
|
||||
} else {
|
||||
@@ -228,13 +228,13 @@ u32 VKRGraphicsPipeline::GetVariantsBitmask() const {
|
||||
}
|
||||
|
||||
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());
|
||||
ERROR_LOG(Log::G3D, "vs: %s\n[END VS]", desc->vertexShaderSource.c_str());
|
||||
ERROR_LOG(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());
|
||||
ERROR_LOG(Log::G3D, "gs: %s\n[END GS]", desc->geometryShaderSource.c_str());
|
||||
}
|
||||
// TODO: Maybe log various other state?
|
||||
ERROR_LOG(G3D, "======== END OF PIPELINE ==========");
|
||||
ERROR_LOG(Log::G3D, "======== END OF PIPELINE ==========");
|
||||
}
|
||||
|
||||
struct SinglePipelineTask {
|
||||
@@ -310,7 +310,7 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan, bool useThread,
|
||||
|
||||
bool VulkanRenderManager::CreateBackbuffers() {
|
||||
if (!vulkan_->GetSwapchain()) {
|
||||
ERROR_LOG(G3D, "No swapchain - can't create backbuffers");
|
||||
ERROR_LOG(Log::G3D, "No swapchain - can't create backbuffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ bool VulkanRenderManager::CreateBackbuffers() {
|
||||
}
|
||||
|
||||
if (newInflightFrames_ != -1) {
|
||||
INFO_LOG(G3D, "Updating inflight frames to %d", newInflightFrames_);
|
||||
INFO_LOG(Log::G3D, "Updating inflight frames to %d", newInflightFrames_);
|
||||
vulkan_->UpdateInflightFrames(newInflightFrames_);
|
||||
newInflightFrames_ = -1;
|
||||
}
|
||||
@@ -356,14 +356,14 @@ void VulkanRenderManager::StartThreads() {
|
||||
runCompileThread_ = true; // For controlling the compiler thread's exit
|
||||
|
||||
if (useRenderThread_) {
|
||||
INFO_LOG(G3D, "Starting Vulkan submission thread");
|
||||
INFO_LOG(Log::G3D, "Starting Vulkan submission thread");
|
||||
renderThread_ = std::thread(&VulkanRenderManager::RenderThreadFunc, this);
|
||||
}
|
||||
INFO_LOG(G3D, "Starting Vulkan compiler thread");
|
||||
INFO_LOG(Log::G3D, "Starting Vulkan compiler thread");
|
||||
compileThread_ = std::thread(&VulkanRenderManager::CompileThreadFunc, this);
|
||||
|
||||
if (measurePresentTime_ && vulkan_->Extensions().KHR_present_wait && vulkan_->GetPresentMode() == VK_PRESENT_MODE_FIFO_KHR) {
|
||||
INFO_LOG(G3D, "Starting Vulkan present wait thread");
|
||||
INFO_LOG(Log::G3D, "Starting Vulkan present wait thread");
|
||||
presentWaitThread_ = std::thread(&VulkanRenderManager::PresentWaitThreadFunc, this);
|
||||
}
|
||||
}
|
||||
@@ -385,7 +385,7 @@ void VulkanRenderManager::StopThreads() {
|
||||
pushCondVar_.notify_one();
|
||||
// Once the render thread encounters the above exit task, it'll exit.
|
||||
renderThread_.join();
|
||||
INFO_LOG(G3D, "Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame());
|
||||
INFO_LOG(Log::G3D, "Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame());
|
||||
}
|
||||
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
@@ -406,7 +406,7 @@ void VulkanRenderManager::StopThreads() {
|
||||
presentWaitThread_.join();
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Vulkan compiler thread joined. Now wait for any straggling compile tasks.");
|
||||
INFO_LOG(Log::G3D, "Vulkan compiler thread joined. Now wait for any straggling compile tasks.");
|
||||
CreateMultiPipelinesTask::WaitForAll();
|
||||
|
||||
{
|
||||
@@ -431,7 +431,7 @@ void VulkanRenderManager::CheckNothingPending() {
|
||||
}
|
||||
|
||||
VulkanRenderManager::~VulkanRenderManager() {
|
||||
INFO_LOG(G3D, "VulkanRenderManager destructor");
|
||||
INFO_LOG(Log::G3D, "VulkanRenderManager destructor");
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(compileMutex_);
|
||||
@@ -507,7 +507,7 @@ void VulkanRenderManager::CompileThreadFunc() {
|
||||
auto &shaders = iter.first;
|
||||
auto &entries = iter.second;
|
||||
|
||||
// NOTICE_LOG(G3D, "For this shader pair, we have %d pipelines to create", (int)entries.size());
|
||||
// NOTICE_LOG(Log::G3D, "For this shader pair, we have %d pipelines to create", (int)entries.size());
|
||||
|
||||
Task *task = new CreateMultiPipelinesTask(vulkan_, entries);
|
||||
g_threadManager.EnqueueTask(task);
|
||||
@@ -563,6 +563,7 @@ void VulkanRenderManager::RenderThreadFunc() {
|
||||
void VulkanRenderManager::PresentWaitThreadFunc() {
|
||||
SetCurrentThreadName("PresentWait");
|
||||
|
||||
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
|
||||
_dbg_assert_(vkWaitForPresentKHR != nullptr);
|
||||
|
||||
uint64_t waitedId = frameIdGen_;
|
||||
@@ -579,8 +580,9 @@ void VulkanRenderManager::PresentWaitThreadFunc() {
|
||||
}
|
||||
_dbg_assert_(waitedId <= frameIdGen_);
|
||||
}
|
||||
#endif
|
||||
|
||||
INFO_LOG(G3D, "Leaving PresentWaitThreadFunc()");
|
||||
INFO_LOG(Log::G3D, "Leaving PresentWaitThreadFunc()");
|
||||
}
|
||||
|
||||
void VulkanRenderManager::PollPresentTiming() {
|
||||
@@ -766,12 +768,12 @@ void VulkanRenderManager::ReportBadStateForDraw() {
|
||||
std::string str = VulkanQueueRunner::StepToString(vulkan_, *curRenderStep_);
|
||||
truncate_cpy(cause2, str.c_str());
|
||||
}
|
||||
ERROR_LOG_REPORT_ONCE(baddraw, G3D, "Can't draw: %s%s. Step count: %d", cause1, cause2, (int)steps_.size());
|
||||
ERROR_LOG_REPORT_ONCE(baddraw, Log::G3D, "Can't draw: %s%s. Step count: %d", cause1, cause2, (int)steps_.size());
|
||||
}
|
||||
|
||||
VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, bool cacheLoad, const char *tag) {
|
||||
if (!desc->vertexShader || !desc->fragmentShader) {
|
||||
ERROR_LOG(G3D, "Can't create graphics pipeline with missing vs/ps: %p %p", desc->vertexShader, desc->fragmentShader);
|
||||
ERROR_LOG(Log::G3D, "Can't create graphics pipeline with missing vs/ps: %p %p", desc->vertexShader, desc->fragmentShader);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -783,7 +785,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe
|
||||
pipelinesToCheck_.push_back(pipeline);
|
||||
} else {
|
||||
if (!variantBitmask) {
|
||||
WARN_LOG(G3D, "WARNING: Will not compile any variants of pipeline, not in renderpass and empty variantBitmask");
|
||||
WARN_LOG(Log::G3D, "WARNING: Will not compile any variants of pipeline, not in renderpass and empty variantBitmask");
|
||||
}
|
||||
// Presumably we're in initialization, loading the shader cache.
|
||||
// Look at variantBitmask to see what variants we should queue up.
|
||||
@@ -801,12 +803,12 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe
|
||||
|
||||
// Sanity check - don't compile incompatible types (could be caused by corrupt caches, changes in data structures, etc).
|
||||
if ((pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) && !RenderPassTypeHasDepth(rpType)) {
|
||||
WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type");
|
||||
WARN_LOG(Log::G3D, "Not compiling pipeline that requires depth, for non depth 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");
|
||||
WARN_LOG(Log::G3D, "Not compiling single sample pipeline for a multisampled render pass type");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -839,7 +841,7 @@ void VulkanRenderManager::EndCurRenderStep() {
|
||||
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());
|
||||
WARN_LOG(Log::G3D, "Trying to render with a depth-writing pipeline to a framebuffer without depth: %s", curRenderStep_->render.framebuffer->Tag());
|
||||
rpType = RenderPassType::DEFAULT;
|
||||
}
|
||||
|
||||
@@ -898,6 +900,7 @@ void VulkanRenderManager::EndCurRenderStep() {
|
||||
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
|
||||
_dbg_assert_(insideFrame_);
|
||||
|
||||
// Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible.
|
||||
if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
|
||||
u32 clearMask = 0;
|
||||
@@ -942,6 +945,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
SanityCheckPassesOnAdd();
|
||||
#endif
|
||||
|
||||
// More redundant bind elimination.
|
||||
if (curRenderStep_) {
|
||||
if (curRenderStep_->commands.empty()) {
|
||||
@@ -1082,7 +1089,7 @@ bool VulkanRenderManager::CopyFramebufferToMemory(VKRFramebuffer *src, VkImageAs
|
||||
} else {
|
||||
// Backbuffer.
|
||||
if (!(vulkan_->GetSurfaceCapabilities().supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
|
||||
ERROR_LOG(G3D, "Copying from backbuffer not supported, can't take screenshots");
|
||||
ERROR_LOG(Log::G3D, "Copying from backbuffer not supported, can't take screenshots");
|
||||
return false;
|
||||
}
|
||||
switch (vulkan_->GetSwapchainFormat()) {
|
||||
@@ -1090,7 +1097,7 @@ bool VulkanRenderManager::CopyFramebufferToMemory(VKRFramebuffer *src, VkImageAs
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; break;
|
||||
// NOTE: If you add supported formats here, make sure to also support them in VulkanQueueRunner::CopyReadbackBuffer.
|
||||
default:
|
||||
ERROR_LOG(G3D, "Unsupported backbuffer format for screenshots");
|
||||
ERROR_LOG(Log::G3D, "Unsupported backbuffer format for screenshots");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1209,7 +1216,7 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten
|
||||
|
||||
if (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
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());
|
||||
WARN_LOG(Log::G3D, "Trying to clear depth/stencil on a non-depth framebuffer: %s", curRenderStep_->render.framebuffer->Tag());
|
||||
} else {
|
||||
curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL;
|
||||
}
|
||||
@@ -1231,6 +1238,10 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten
|
||||
}
|
||||
|
||||
void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag) {
|
||||
#ifdef _DEBUG
|
||||
SanityCheckPassesOnAdd();
|
||||
#endif
|
||||
|
||||
_dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x);
|
||||
_dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y);
|
||||
_dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width);
|
||||
@@ -1295,6 +1306,10 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag) {
|
||||
#ifdef _DEBUG
|
||||
SanityCheckPassesOnAdd();
|
||||
#endif
|
||||
|
||||
_dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x);
|
||||
_dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y);
|
||||
_dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width);
|
||||
@@ -1847,3 +1862,14 @@ void VKRPipelineLayout::FlushDescSets(VulkanContext *vulkan, int frame, QueuePro
|
||||
profile->descriptorsWritten += writeCount;
|
||||
profile->descriptorsDeduped += dedupCount;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::SanityCheckPassesOnAdd() {
|
||||
#if _DEBUG
|
||||
// Check that we don't have any previous passes that write to the backbuffer, that must ALWAYS be the last one.
|
||||
for (int i = 0; i < steps_.size(); i++) {
|
||||
if (steps_[i]->stepType == VKRStepType::RENDER) {
|
||||
_dbg_assert_(steps_[i]->render.framebuffer != nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -90,6 +90,7 @@ public:
|
||||
VkDynamicState dynamicStates[6]{};
|
||||
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT rs_provoking{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT };
|
||||
|
||||
// Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish.
|
||||
Promise<VkShaderModule> *vertexShader = nullptr;
|
||||
@@ -533,6 +534,10 @@ public:
|
||||
void StartThreads();
|
||||
void StopThreads();
|
||||
|
||||
size_t GetNumSteps() const {
|
||||
return steps_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
void EndCurRenderStep();
|
||||
|
||||
@@ -550,6 +555,8 @@ private:
|
||||
void ResetDescriptorLists(int frame);
|
||||
void FlushDescriptors(int frame);
|
||||
|
||||
void SanityCheckPassesOnAdd();
|
||||
|
||||
FrameDataShared frameDataShared_;
|
||||
|
||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
||||
|
||||
@@ -221,7 +221,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con
|
||||
std::vector<uint32_t> spirv;
|
||||
std::string errorMessage;
|
||||
if (!GLSLtoSPV(vkstage_, source_.c_str(), GLSLVariant::VULKAN, spirv, &errorMessage)) {
|
||||
WARN_LOG(G3D, "Shader compile to module failed (%s): %s", tag_.c_str(), errorMessage.c_str());
|
||||
WARN_LOG(Log::G3D, "Shader compile to module failed (%s): %s", tag_.c_str(), errorMessage.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con
|
||||
module_ = Promise<VkShaderModule>::AlreadyDone(shaderModule);
|
||||
ok_ = true;
|
||||
} else {
|
||||
WARN_LOG(G3D, "vkCreateShaderModule failed (%s)", tag_.c_str());
|
||||
WARN_LOG(Log::G3D, "vkCreateShaderModule failed (%s)", tag_.c_str());
|
||||
ok_ = false;
|
||||
}
|
||||
return ok_;
|
||||
@@ -380,6 +380,13 @@ public:
|
||||
VKContext(VulkanContext *vulkan, bool useRenderThread);
|
||||
~VKContext();
|
||||
|
||||
BackendState GetCurrentBackendState() const override {
|
||||
return BackendState{
|
||||
(u32)renderManager_.GetNumSteps(),
|
||||
true,
|
||||
};
|
||||
}
|
||||
|
||||
void DebugAnnotate(const char *annotation) override;
|
||||
void Wait() override {
|
||||
vkDeviceWaitIdle(vulkan_->GetDevice());
|
||||
@@ -699,8 +706,10 @@ VulkanTexture *VKContext::GetNullTexture() {
|
||||
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,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
VulkanBarrierBatch barrier;
|
||||
nullTexture_->CreateDirect(w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, &barrier);
|
||||
barrier.Flush(cmdInit);
|
||||
uint32_t bindOffset;
|
||||
VkBuffer bindBuf;
|
||||
uint32_t *data = (uint32_t *)push_->Allocate(w * h * 4, 4, &bindBuf, &bindOffset);
|
||||
@@ -772,7 +781,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, Vu
|
||||
// Zero-sized textures not allowed.
|
||||
_assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1!
|
||||
if (desc.width * desc.height * desc.depth <= 0) {
|
||||
ERROR_LOG(G3D, "Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth);
|
||||
ERROR_LOG(Log::G3D, "Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth);
|
||||
return false;
|
||||
}
|
||||
_dbg_assert_(pushBuffer);
|
||||
@@ -791,10 +800,12 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, Vu
|
||||
|
||||
VkComponentMapping r8AsAlpha[4] = { VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_R };
|
||||
|
||||
if (!vkTex_->CreateDirect(cmd, width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits, desc.swizzle == TextureSwizzle::R8_AS_ALPHA ? r8AsAlpha : nullptr)) {
|
||||
ERROR_LOG(G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_);
|
||||
VulkanBarrierBatch barrier;
|
||||
if (!vkTex_->CreateDirect(width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits, &barrier, desc.swizzle == TextureSwizzle::R8_AS_ALPHA ? r8AsAlpha : nullptr)) {
|
||||
ERROR_LOG(Log::G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_);
|
||||
return false;
|
||||
}
|
||||
barrier.Flush(cmd);
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
if (desc.initData.size()) {
|
||||
UpdateInternal(cmd, pushBuffer, desc.initData.data(), desc.initDataCallback, (int)desc.initData.size());
|
||||
@@ -902,6 +913,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
|
||||
caps_.sampleRateShadingSupported = vulkan->GetDeviceFeatures().enabled.standard.sampleRateShading != 0;
|
||||
caps_.textureSwizzleSupported = true;
|
||||
|
||||
// Note that it must also be enabled on the pipelines (which we do).
|
||||
caps_.provokingVertexLast = vulkan->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast;
|
||||
|
||||
// Present mode stuff
|
||||
caps_.presentMaxInterval = 1;
|
||||
caps_.presentInstantModeChange = false; // TODO: Fix this with some work in VulkanContext
|
||||
@@ -929,7 +943,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
|
||||
case VULKAN_VENDOR_APPLE: caps_.vendor = GPUVendor::VENDOR_APPLE; break;
|
||||
case VULKAN_VENDOR_MESA: caps_.vendor = GPUVendor::VENDOR_MESA; break;
|
||||
default:
|
||||
WARN_LOG(G3D, "Unknown vendor ID %08x", deviceProps.vendorID);
|
||||
WARN_LOG(Log::G3D, "Unknown vendor ID %08x", deviceProps.vendorID);
|
||||
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
@@ -1040,11 +1054,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
|
||||
}
|
||||
|
||||
if (!vulkan->Extensions().KHR_depth_stencil_resolve) {
|
||||
INFO_LOG(G3D, "KHR_depth_stencil_resolve not supported, disabling multisampling");
|
||||
INFO_LOG(Log::G3D, "KHR_depth_stencil_resolve not supported, disabling multisampling");
|
||||
}
|
||||
|
||||
bugs_.Infest(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI);
|
||||
|
||||
// We limit multisampling functionality to reasonably recent and known-good tiling GPUs.
|
||||
if (multisampleAllowed) {
|
||||
// Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess
|
||||
@@ -1053,9 +1065,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
|
||||
const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve;
|
||||
if (((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) {
|
||||
caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts);
|
||||
INFO_LOG(G3D, "Multisample levels mask: %d", caps_.multiSampleLevelsMask);
|
||||
INFO_LOG(Log::G3D, "Multisample levels mask: %d", caps_.multiSampleLevelsMask);
|
||||
} else {
|
||||
INFO_LOG(G3D, "Not enough depth/stencil resolve modes supported, disabling multisampling.");
|
||||
INFO_LOG(Log::G3D, "Not enough depth/stencil resolve modes supported, disabling multisampling.");
|
||||
caps_.multiSampleLevelsMask = 1;
|
||||
}
|
||||
} else {
|
||||
@@ -1187,7 +1199,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
} else if (vkshader->GetStage() == ShaderStage::Fragment) {
|
||||
gDesc.fragmentShader = vkshader->Get();
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Bad stage");
|
||||
ERROR_LOG(Log::G3D, "Bad stage");
|
||||
delete pipeline;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1212,8 +1224,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
|
||||
gDesc.dss = depth->info;
|
||||
|
||||
raster->ToVulkan(&gDesc.rs);
|
||||
|
||||
// Copy bindings from input layout.
|
||||
gDesc.topology = primToVK[(int)desc.prim];
|
||||
|
||||
@@ -1235,6 +1245,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
raster->ToVulkan(&gDesc.rs);
|
||||
|
||||
if (renderManager_.GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
|
||||
ChainStruct(gDesc.rs, &gDesc.rs_provoking);
|
||||
gDesc.rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
|
||||
}
|
||||
|
||||
pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, false, tag ? tag : "thin3d");
|
||||
|
||||
if (desc.uniformDesc) {
|
||||
@@ -1300,14 +1315,14 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) {
|
||||
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
|
||||
if (!push_ || !initCmd) {
|
||||
// Too early! Fail.
|
||||
ERROR_LOG(G3D, "Can't create textures before the first frame has started.");
|
||||
ERROR_LOG(Log::G3D, "Can't create textures before the first frame has started.");
|
||||
return nullptr;
|
||||
}
|
||||
VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc);
|
||||
if (tex->Create(initCmd, &renderManager_.PostInitBarrier(), push_, desc)) {
|
||||
return tex;
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed to create texture");
|
||||
ERROR_LOG(Log::G3D, "Failed to create texture");
|
||||
tex->Release();
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1317,7 +1332,7 @@ void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, Text
|
||||
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
|
||||
if (!push_ || !initCmd) {
|
||||
// Too early! Fail.
|
||||
ERROR_LOG(G3D, "Can't create textures before the first frame has started.");
|
||||
ERROR_LOG(Log::G3D, "Can't create textures before the first frame has started.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1429,7 +1444,7 @@ ShaderModule *VKContext::CreateShaderModule(ShaderStage stage, ShaderLanguage la
|
||||
if (shader->Compile(vulkan_, language, data, size)) {
|
||||
return shader;
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed to compile shader %s:\n%s", tag, (const char *)LineNumberString((const char *)data).c_str());
|
||||
ERROR_LOG(Log::G3D, "Failed to compile shader %s:\n%s", tag, (const char *)LineNumberString((const char *)data).c_str());
|
||||
shader->Release();
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1555,6 +1570,7 @@ std::vector<std::string> VKContext::GetFeatureList() const {
|
||||
AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader);
|
||||
AddFeature(features, "presentId", vulkan_->GetDeviceFeatures().available.presentId.presentId, vulkan_->GetDeviceFeatures().enabled.presentId.presentId);
|
||||
AddFeature(features, "presentWait", vulkan_->GetDeviceFeatures().available.presentWait.presentWait, vulkan_->GetDeviceFeatures().enabled.presentWait.presentWait);
|
||||
AddFeature(features, "provokingVertexLast", vulkan_->GetDeviceFeatures().available.provokingVertex.provokingVertexLast, vulkan_->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast);
|
||||
|
||||
features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat));
|
||||
|
||||
|
||||
@@ -601,7 +601,7 @@ void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u
|
||||
case Draw::DataFormat::R8G8B8A8_UNORM:
|
||||
case Draw::DataFormat::UNDEFINED:
|
||||
default:
|
||||
WARN_LOG(G3D, "Unable to convert from format: %d", (int)format);
|
||||
WARN_LOG(Log::G3D, "Unable to convert from format: %d", (int)format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -663,7 +663,7 @@ void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u
|
||||
case Draw::DataFormat::R8G8B8A8_UNORM:
|
||||
case Draw::DataFormat::UNDEFINED:
|
||||
default:
|
||||
WARN_LOG(G3D, "Unable to convert from format to BGRA: %d", (int)format);
|
||||
WARN_LOG(Log::G3D, "Unable to convert from format to BGRA: %d", (int)format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -612,7 +612,7 @@ struct DeviceCaps {
|
||||
bool setMaxFrameLatencySupported;
|
||||
bool textureSwizzleSupported;
|
||||
bool requiresHalfPixelOffset;
|
||||
|
||||
bool provokingVertexLast; // GL behavior, what the PSP does
|
||||
bool verySlowShaderCompiler;
|
||||
|
||||
// From the other backends, we can detect if D3D9 support is known bad (like on Xe) and disable it.
|
||||
@@ -687,6 +687,11 @@ enum class DebugFlags {
|
||||
};
|
||||
ENUM_CLASS_BITOPS(DebugFlags);
|
||||
|
||||
struct BackendState {
|
||||
u32 passes;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
class DrawContext {
|
||||
public:
|
||||
virtual ~DrawContext();
|
||||
@@ -705,6 +710,10 @@ public:
|
||||
virtual std::vector<std::string> GetPresentModeList(std::string_view currentMarkerString) const { return std::vector<std::string>(); }
|
||||
virtual std::vector<std::string> GetSurfaceFormatList() const { return std::vector<std::string>(); }
|
||||
|
||||
virtual BackendState GetCurrentBackendState() const {
|
||||
return BackendState{};
|
||||
}
|
||||
|
||||
// Describes the primary shader language that this implementation prefers.
|
||||
const ShaderLanguageDesc &GetShaderLanguageDesc() {
|
||||
return shaderLanguageDesc_;
|
||||
|
||||
@@ -26,7 +26,6 @@ const char *GetDeviceName(int deviceId) {
|
||||
case DEVICE_ID_XINPUT_3: return "x360_4";
|
||||
case DEVICE_ID_ACCELEROMETER: return "accelerometer";
|
||||
case DEVICE_ID_MOUSE: return "mouse";
|
||||
case DEVICE_ID_XR_HMD: return "xr_hmd";
|
||||
case DEVICE_ID_XR_CONTROLLER_LEFT: return "xr_l";
|
||||
case DEVICE_ID_XR_CONTROLLER_RIGHT: return "xr_r";
|
||||
default:
|
||||
|
||||
@@ -32,7 +32,6 @@ enum InputDeviceID {
|
||||
DEVICE_ID_XINPUT_2 = 22,
|
||||
DEVICE_ID_XINPUT_3 = 23,
|
||||
DEVICE_ID_ACCELEROMETER = 30, // no longer used
|
||||
DEVICE_ID_XR_HMD = 39,
|
||||
DEVICE_ID_XR_CONTROLLER_LEFT = 40,
|
||||
DEVICE_ID_XR_CONTROLLER_RIGHT = 41,
|
||||
DEVICE_ID_TOUCH = 42,
|
||||
|
||||
@@ -246,19 +246,6 @@ enum InputKeyCode {
|
||||
NKCODE_EXT_MOUSEWHEEL_UP = 1008,
|
||||
NKCODE_EXT_MOUSEWHEEL_DOWN = 1009,
|
||||
|
||||
// Virtual reality 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,
|
||||
|
||||
// Virtual reality rotation
|
||||
NKCODE_EXT_ROTATION_UP = 1111,
|
||||
NKCODE_EXT_ROTATION_DOWN = 1112,
|
||||
NKCODE_EXT_ROTATION_LEFT = 1113,
|
||||
NKCODE_EXT_ROTATION_RIGHT = 1114,
|
||||
|
||||
NKCODE_MAX
|
||||
};
|
||||
|
||||
|
||||
+16
-6
@@ -37,9 +37,10 @@
|
||||
|
||||
static bool hitAnyAsserts = false;
|
||||
|
||||
std::mutex g_extraAssertInfoMutex;
|
||||
std::string g_extraAssertInfo = "menu";
|
||||
double g_assertInfoTime = 0.0;
|
||||
static std::mutex g_extraAssertInfoMutex;
|
||||
static std::string g_extraAssertInfo = "menu";
|
||||
static double g_assertInfoTime = 0.0;
|
||||
static bool g_exitOnAssert;
|
||||
|
||||
void SetExtraAssertInfo(const char *info) {
|
||||
std::lock_guard<std::mutex> guard(g_extraAssertInfoMutex);
|
||||
@@ -47,6 +48,10 @@ void SetExtraAssertInfo(const char *info) {
|
||||
g_assertInfoTime = time_now_d();
|
||||
}
|
||||
|
||||
void SetCleanExitOnAssert() {
|
||||
g_exitOnAssert = true;
|
||||
}
|
||||
|
||||
bool HandleAssert(const char *function, const char *file, int line, const char *expression, const char* format, ...) {
|
||||
// Read message and write it to the log
|
||||
char text[LOG_BUF_SIZE];
|
||||
@@ -65,8 +70,8 @@ bool HandleAssert(const char *function, const char *file, int line, const char *
|
||||
}
|
||||
|
||||
// Normal logging (will also log to Android log)
|
||||
ERROR_LOG(SYSTEM, "%s", formatted);
|
||||
// Also do a simple printf for good measure, in case logging of SYSTEM is disabled (should we disallow that?)
|
||||
ERROR_LOG(Log::System, "%s", formatted);
|
||||
// Also do a simple printf for good measure, in case logging of System is disabled (should we disallow that?)
|
||||
fprintf(stderr, "%s\n", formatted);
|
||||
|
||||
hitAnyAsserts = true;
|
||||
@@ -78,8 +83,13 @@ bool HandleAssert(const char *function, const char *file, int line, const char *
|
||||
std::wstring wtext = ConvertUTF8ToWString(formatted) + L"\n\nTry to continue?";
|
||||
std::wstring wcaption = ConvertUTF8ToWString(std::string(caption) + " " + GetCurrentThreadName());
|
||||
OutputDebugString(wtext.c_str());
|
||||
printf("%s\n", formatted);
|
||||
if (IDYES != MessageBox(0, wtext.c_str(), wcaption.c_str(), msgBoxStyle)) {
|
||||
return false;
|
||||
if (g_exitOnAssert) {
|
||||
// Hard exit.
|
||||
ExitProcess(1);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
+36
-36
@@ -27,41 +27,41 @@
|
||||
#define VERBOSE_LEVEL 6 // Noisy debugging - sometimes needed but usually unimportant.
|
||||
|
||||
// NOTE: Needs to be kept in sync with the g_logTypeNames array.
|
||||
enum class LogType {
|
||||
SYSTEM = 0, // Catch-all for uncategorized things
|
||||
BOOT,
|
||||
COMMON,
|
||||
enum class Log {
|
||||
System = 0, // Catch-all for uncategorized things
|
||||
Boot,
|
||||
Common,
|
||||
CPU,
|
||||
FILESYS,
|
||||
FileSystem,
|
||||
G3D,
|
||||
HLE, // dumping ground that we should get rid of
|
||||
JIT,
|
||||
LOADER,
|
||||
Loader,
|
||||
ME,
|
||||
MEMMAP,
|
||||
SASMIX,
|
||||
SAVESTATE,
|
||||
FRAMEBUF,
|
||||
AUDIO,
|
||||
MemMap,
|
||||
SasMix,
|
||||
SaveState,
|
||||
FrameBuf,
|
||||
Audio,
|
||||
IO,
|
||||
ACHIEVEMENTS,
|
||||
Achievements,
|
||||
HTTP,
|
||||
PRINTF,
|
||||
Printf,
|
||||
|
||||
SCEAUDIO,
|
||||
SCECTRL,
|
||||
SCEDISPLAY,
|
||||
SCEFONT,
|
||||
SCEGE,
|
||||
SCEINTC,
|
||||
SCEIO,
|
||||
SCEKERNEL,
|
||||
SCEMODULE,
|
||||
SCENET,
|
||||
SCERTC,
|
||||
SCESAS,
|
||||
SCEUTILITY,
|
||||
SCEMISC,
|
||||
sceAudio,
|
||||
sceCtrl,
|
||||
sceDisplay,
|
||||
sceFont,
|
||||
sceGe,
|
||||
sceIntc,
|
||||
sceIo,
|
||||
sceKernel,
|
||||
sceModule,
|
||||
sceNet,
|
||||
sceRtc,
|
||||
sceSas,
|
||||
sceUtility,
|
||||
sceMisc,
|
||||
|
||||
NUMBER_OF_LOGS, // Must be last
|
||||
};
|
||||
@@ -75,13 +75,12 @@ enum class LogLevel : int {
|
||||
LVERBOSE = VERBOSE_LEVEL,
|
||||
};
|
||||
|
||||
void GenericLog(LogLevel level, LogType type,
|
||||
const char *file, int line, const char *fmt, ...)
|
||||
void GenericLog(LogLevel level, Log type, const char *file, int line, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
#endif
|
||||
;
|
||||
bool GenericLogEnabled(LogLevel level, LogType type);
|
||||
bool GenericLogEnabled(LogLevel level, Log type);
|
||||
|
||||
// Exception for Windows - enable more log levels in release mode than on other platforms.
|
||||
#if defined(_DEBUG) || defined(_WIN32)
|
||||
@@ -104,12 +103,12 @@ bool GenericLogEnabled(LogLevel level, LogType type);
|
||||
GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define ERROR_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LERROR, __VA_ARGS__) } while (false)
|
||||
#define WARN_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LWARNING, __VA_ARGS__) } while (false)
|
||||
#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LNOTICE, __VA_ARGS__) } while (false)
|
||||
#define INFO_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LINFO, __VA_ARGS__) } while (false)
|
||||
#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LDEBUG, __VA_ARGS__) } while (false)
|
||||
#define VERBOSE_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LVERBOSE, __VA_ARGS__) } while (false)
|
||||
#define ERROR_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LERROR, __VA_ARGS__) } while (false)
|
||||
#define WARN_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LWARNING, __VA_ARGS__) } while (false)
|
||||
#define NOTICE_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LNOTICE, __VA_ARGS__) } while (false)
|
||||
#define INFO_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LINFO, __VA_ARGS__) } while (false)
|
||||
#define DEBUG_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LDEBUG, __VA_ARGS__) } while (false)
|
||||
#define VERBOSE_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LVERBOSE, __VA_ARGS__) } while (false)
|
||||
|
||||
// Currently only actually shows a dialog box on Windows.
|
||||
bool HandleAssert(const char *function, const char *file, int line, const char *expression, const char* format, ...)
|
||||
@@ -121,6 +120,7 @@ __attribute__((format(printf, 5, 6)))
|
||||
bool HitAnyAsserts();
|
||||
void ResetHitAnyAsserts();
|
||||
void SetExtraAssertInfo(const char *info);
|
||||
void SetCleanExitOnAssert();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Tricky macro to get the basename, that also works if *built* on Win32.
|
||||
|
||||
@@ -15,85 +15,64 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
#include <atomic>
|
||||
#include <algorithm> // min
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <string> // System: To be able to add strings with "+"
|
||||
#include <math.h>
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
#include "CommonWindows.h"
|
||||
#include <array>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/ConsoleListener.h"
|
||||
#include "Common/Log/ConsoleListener.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#if defined(USING_WIN_UI)
|
||||
const int LOG_PENDING_MAX = 120 * 10000;
|
||||
const int LOG_LATENCY_DELAY_MS = 20;
|
||||
const int LOG_SHUTDOWN_DELAY_MS = 250;
|
||||
const int LOG_MAX_DISPLAY_LINES = 4000;
|
||||
|
||||
int ConsoleListener::refCount = 0;
|
||||
HANDLE ConsoleListener::hThread = NULL;
|
||||
HANDLE ConsoleListener::hTriggerEvent = NULL;
|
||||
CRITICAL_SECTION ConsoleListener::criticalSection;
|
||||
static bool g_Initialized;
|
||||
|
||||
char *ConsoleListener::logPending = NULL;
|
||||
std::atomic<uint32_t> ConsoleListener::logPendingReadPos;
|
||||
std::atomic<uint32_t> ConsoleListener::logPendingWritePos;
|
||||
#endif
|
||||
ConsoleListener::ConsoleListener() : hidden_(true) {
|
||||
useColor_ = true;
|
||||
|
||||
ConsoleListener::ConsoleListener() : bHidden(true)
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
hConsole = NULL;
|
||||
bUseColor = true;
|
||||
if (hTriggerEvent == NULL) {
|
||||
hTriggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
// useThread_ = false;
|
||||
|
||||
if (useThread_ && !hTriggerEvent) {
|
||||
hTriggerEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
InitializeCriticalSection(&criticalSection);
|
||||
logPending = new char[LOG_PENDING_MAX];
|
||||
logPending_ = new char[LOG_PENDING_MAX];
|
||||
}
|
||||
++refCount;
|
||||
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(SWITCH)
|
||||
bUseColor = false;
|
||||
#elif defined(_MSC_VER)
|
||||
bUseColor = false;
|
||||
#elif defined(__APPLE__)
|
||||
// Xcode builtin terminal used for debugging does not support colours.
|
||||
// Fortunately it can be detected with a TERM env variable.
|
||||
bUseColor = isatty(fileno(stdout)) && getenv("TERM") != NULL;
|
||||
#else
|
||||
bUseColor = isatty(fileno(stdout));
|
||||
#endif
|
||||
|
||||
_dbg_assert_(!g_Initialized);
|
||||
g_Initialized = true;
|
||||
|
||||
logPendingReadPos_.store(0);
|
||||
logPendingWritePos_.store(0);
|
||||
}
|
||||
|
||||
ConsoleListener::~ConsoleListener()
|
||||
{
|
||||
ConsoleListener::~ConsoleListener() {
|
||||
g_Initialized = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Handle console event
|
||||
bool WINAPI ConsoleHandler(DWORD msgType)
|
||||
{
|
||||
if (msgType == CTRL_C_EVENT)
|
||||
{
|
||||
bool WINAPI ConsoleHandler(DWORD msgType) {
|
||||
if (msgType == CTRL_C_EVENT) {
|
||||
OutputDebugString(L"Ctrl-C!\n");
|
||||
return TRUE;
|
||||
}
|
||||
else if (msgType == CTRL_CLOSE_EVENT)
|
||||
{
|
||||
} else if (msgType == CTRL_CLOSE_EVENT) {
|
||||
OutputDebugString(L"Close console window!\n");
|
||||
return TRUE;
|
||||
}
|
||||
@@ -105,156 +84,110 @@ bool WINAPI ConsoleHandler(DWORD msgType)
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// 100, 100, "Dolphin Log Console"
|
||||
// Open console window - width and height is the size of console window
|
||||
// Name is the window title
|
||||
void ConsoleListener::Init(bool AutoOpen, int Width, int Height, const char *Title)
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
void ConsoleListener::Init(bool AutoOpen, int Width, int Height) {
|
||||
openWidth_ = Width;
|
||||
openHeight_ = Height;
|
||||
title_ = ConvertUTF8ToWString(Title);
|
||||
|
||||
if (AutoOpen)
|
||||
{
|
||||
if (AutoOpen) {
|
||||
Open();
|
||||
bHidden = false;
|
||||
hidden_ = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConsoleListener::Open()
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
if (!GetConsoleWindow())
|
||||
{
|
||||
void ConsoleListener::Open() {
|
||||
if (!GetConsoleWindow()) {
|
||||
// Open the console window and create the window handle for GetStdHandle()
|
||||
AllocConsole();
|
||||
hWnd = GetConsoleWindow();
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
// disable console close button
|
||||
HMENU hMenu=GetSystemMenu(hWnd, false);
|
||||
HMENU hMenu = GetSystemMenu(hWnd, false);
|
||||
EnableMenuItem(hMenu,SC_CLOSE,MF_GRAYED|MF_BYCOMMAND);
|
||||
// Save the window handle that AllocConsole() created
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
// Set console handler
|
||||
if(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE)){OutputDebugString(L"Console handler is installed!\n");}
|
||||
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE)) {
|
||||
OutputDebugStringA("Console handler is installed!\n");
|
||||
}
|
||||
// Set the console window title
|
||||
SetConsoleTitle(title_.c_str());
|
||||
SetConsoleTitle(L"PPSSPP Debug Console");
|
||||
SetConsoleCP(CP_UTF8);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
// Set letter space
|
||||
LetterSpace(openWidth_, LOG_MAX_DISPLAY_LINES);
|
||||
//MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
if (hTriggerEvent != NULL && hThread == NULL)
|
||||
hThread = (HANDLE)_beginthreadex(NULL, 0, &ConsoleListener::RunThread, this, 0, NULL);
|
||||
#endif
|
||||
if (useThread_ && hTriggerEvent != NULL && !thread_.joinable()) {
|
||||
thread_ = std::thread([&] {
|
||||
SetCurrentThreadName("Console");
|
||||
LogWriterThread();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleListener::Show(bool bShow)
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
if (bShow && bHidden)
|
||||
{
|
||||
if (!IsOpen())
|
||||
void ConsoleListener::Show(bool bShow) {
|
||||
if (bShow && hidden_) {
|
||||
if (!IsOpen()) {
|
||||
Open();
|
||||
}
|
||||
ShowWindow(GetConsoleWindow(), SW_SHOW);
|
||||
bHidden = false;
|
||||
}
|
||||
else if (!bShow && !bHidden)
|
||||
{
|
||||
hidden_ = false;
|
||||
} else if (!bShow && !hidden_) {
|
||||
ShowWindow(GetConsoleWindow(), SW_HIDE);
|
||||
bHidden = true;
|
||||
hidden_ = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ConsoleListener::UpdateHandle()
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
void ConsoleListener::UpdateHandle() {
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Close the console window and close the eventual file handle
|
||||
void ConsoleListener::Close()
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
|
||||
if (--refCount <= 0)
|
||||
{
|
||||
if (hThread != NULL)
|
||||
{
|
||||
logPendingWritePos.store((u32)-1, std::memory_order_release);
|
||||
|
||||
SetEvent(hTriggerEvent);
|
||||
WaitForSingleObject(hThread, LOG_SHUTDOWN_DELAY_MS);
|
||||
CloseHandle(hThread);
|
||||
hThread = NULL;
|
||||
}
|
||||
if (hTriggerEvent != NULL)
|
||||
{
|
||||
DeleteCriticalSection(&criticalSection);
|
||||
CloseHandle(hTriggerEvent);
|
||||
hTriggerEvent = NULL;
|
||||
}
|
||||
if (logPending != NULL)
|
||||
{
|
||||
delete [] logPending;
|
||||
logPending = NULL;
|
||||
}
|
||||
refCount = 0;
|
||||
void ConsoleListener::Close() {
|
||||
if (thread_.joinable()) {
|
||||
logPendingWritePos_.store((u32)-1, std::memory_order_release);
|
||||
SetEvent(hTriggerEvent);
|
||||
thread_.join();
|
||||
}
|
||||
if (hTriggerEvent) {
|
||||
DeleteCriticalSection(&criticalSection);
|
||||
CloseHandle(hTriggerEvent);
|
||||
hTriggerEvent = nullptr;
|
||||
}
|
||||
if (logPending_) {
|
||||
delete [] logPending_;
|
||||
logPending_ = nullptr;
|
||||
}
|
||||
|
||||
if (hConsole != NULL) {
|
||||
if (hConsole) {
|
||||
FreeConsole();
|
||||
hConsole = NULL;
|
||||
hConsole = nullptr;
|
||||
}
|
||||
#else
|
||||
fflush(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ConsoleListener::IsOpen()
|
||||
{
|
||||
#if defined(USING_WIN_UI)
|
||||
return (hConsole != NULL);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
bool ConsoleListener::IsOpen() {
|
||||
return (hConsole != nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are
|
||||
dependent on each other, that's the reason for the additional checks.
|
||||
*/
|
||||
void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst)
|
||||
{
|
||||
// LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are
|
||||
// dependent on each other, that's the reason for the additional checks.
|
||||
void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) {
|
||||
_dbg_assert_msg_(IsOpen(), "Don't call this before opening the console.");
|
||||
#if defined(USING_WIN_UI)
|
||||
BOOL SB, SW;
|
||||
if (BufferFirst)
|
||||
{
|
||||
if (BufferFirst) {
|
||||
// Change screen buffer size
|
||||
COORD Co = {(SHORT)BufferWidth, (SHORT)BufferHeight};
|
||||
SB = SetConsoleScreenBufferSize(hConsole, Co);
|
||||
// Change the screen buffer window size
|
||||
SMALL_RECT coo = {(SHORT)0, (SHORT)0, (SHORT)ScreenWidth, (SHORT)ScreenHeight}; // top, left, right, bottom
|
||||
SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Change the screen buffer window size
|
||||
SMALL_RECT coo = {(SHORT)0, (SHORT)0, (SHORT)ScreenWidth, (SHORT)ScreenHeight}; // top, left, right, bottom
|
||||
SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
|
||||
@@ -262,22 +195,19 @@ void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int S
|
||||
COORD Co = {(SHORT)BufferWidth, (SHORT)BufferHeight};
|
||||
SB = SetConsoleScreenBufferSize(hConsole, Co);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void ConsoleListener::LetterSpace(int Width, int Height)
|
||||
{
|
||||
|
||||
void ConsoleListener::LetterSpace(int Width, int Height) {
|
||||
_dbg_assert_msg_(IsOpen(), "Don't call this before opening the console.");
|
||||
#if defined(USING_WIN_UI)
|
||||
// Get console info
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
|
||||
GetConsoleScreenBufferInfo(hConsole, &ConInfo);
|
||||
|
||||
//
|
||||
int OldBufferWidth = ConInfo.dwSize.X;
|
||||
int OldBufferHeight = ConInfo.dwSize.Y;
|
||||
int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left);
|
||||
int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top);
|
||||
//
|
||||
|
||||
int NewBufferWidth = Width;
|
||||
int NewBufferHeight = Height;
|
||||
int NewScreenWidth = NewBufferWidth - 1;
|
||||
@@ -289,13 +219,10 @@ void ConsoleListener::LetterSpace(int Width, int Height)
|
||||
BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1));
|
||||
|
||||
// Resize the window too
|
||||
//MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true);
|
||||
#endif
|
||||
// MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true);
|
||||
}
|
||||
|
||||
#if defined(USING_WIN_UI)
|
||||
COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth)
|
||||
{
|
||||
COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) {
|
||||
COORD Ret = {0, 0};
|
||||
// Full rows
|
||||
int Step = (int)floor((float)BytesRead / (float)BufferWidth);
|
||||
@@ -305,76 +232,65 @@ COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth)
|
||||
return Ret;
|
||||
}
|
||||
|
||||
unsigned int WINAPI ConsoleListener::RunThread(void *lpParam)
|
||||
{
|
||||
SetCurrentThreadName("Console");
|
||||
ConsoleListener *consoleLog = (ConsoleListener *)lpParam;
|
||||
consoleLog->LogWriterThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConsoleListener::LogWriterThread()
|
||||
{
|
||||
void ConsoleListener::LogWriterThread() {
|
||||
char *logLocal = new char[LOG_PENDING_MAX];
|
||||
int logLocalSize = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
WaitForSingleObject(hTriggerEvent, INFINITE);
|
||||
Sleep(LOG_LATENCY_DELAY_MS);
|
||||
|
||||
u32 logRemotePos = logPendingWritePos.load(std::memory_order_acquire);
|
||||
if (logRemotePos == (u32) -1)
|
||||
u32 logRemotePos = logPendingWritePos_.load(std::memory_order_acquire);
|
||||
if (logRemotePos == (u32)-1) {
|
||||
break;
|
||||
else if (logRemotePos == logPendingReadPos)
|
||||
} else if (logRemotePos == logPendingReadPos_) {
|
||||
continue;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
EnterCriticalSection(&criticalSection);
|
||||
logRemotePos = logPendingWritePos.load(std::memory_order_acquire);
|
||||
logRemotePos = logPendingWritePos_.load(std::memory_order_acquire);
|
||||
|
||||
int start = 0;
|
||||
if (logRemotePos < logPendingReadPos)
|
||||
{
|
||||
const int count = LOG_PENDING_MAX - logPendingReadPos;
|
||||
memcpy(logLocal + start, logPending + logPendingReadPos, count);
|
||||
if (logRemotePos < logPendingReadPos_) {
|
||||
const int count = LOG_PENDING_MAX - logPendingReadPos_;
|
||||
memcpy(logLocal + start, logPending_ + logPendingReadPos_, count);
|
||||
|
||||
start = count;
|
||||
logPendingReadPos = 0;
|
||||
logPendingReadPos_ = 0;
|
||||
}
|
||||
|
||||
const int count = logRemotePos - logPendingReadPos;
|
||||
memcpy(logLocal + start, logPending + logPendingReadPos, count);
|
||||
const int count = logRemotePos - logPendingReadPos_;
|
||||
memcpy(logLocal + start, logPending_ + logPendingReadPos_, count);
|
||||
|
||||
logPendingReadPos += count;
|
||||
logPendingReadPos_ += count;
|
||||
LeaveCriticalSection(&criticalSection);
|
||||
|
||||
// Double check.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
if (logPendingWritePos_ == (u32)-1) {
|
||||
break;
|
||||
}
|
||||
|
||||
logLocalSize = start + count;
|
||||
}
|
||||
|
||||
for (char *Text = logLocal, *End = logLocal + logLocalSize; Text < End; )
|
||||
{
|
||||
for (char *Text = logLocal, *End = logLocal + logLocalSize; Text < End; ) {
|
||||
LogLevel Level = LogLevel::LINFO;
|
||||
|
||||
char *next = (char *) memchr(Text + 1, '\033', End - Text);
|
||||
size_t Len = next - Text;
|
||||
if (next == NULL)
|
||||
if (!next) {
|
||||
Len = End - Text;
|
||||
}
|
||||
|
||||
if (Text[0] == '\033' && Text + 1 < End)
|
||||
{
|
||||
if (Text[0] == '\033' && Text + 1 < End) {
|
||||
Level = (LogLevel)(Text[1] - '0');
|
||||
Len -= 2;
|
||||
Text += 2;
|
||||
}
|
||||
|
||||
// Make sure we didn't start quitting. This is kinda slow.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
// Make sure we didn't start quitting. This is kinda slow.
|
||||
if (logPendingWritePos_ == (u32)-1) {
|
||||
break;
|
||||
}
|
||||
|
||||
WriteToConsole(Level, Text, Len);
|
||||
Text += Len;
|
||||
@@ -384,11 +300,11 @@ void ConsoleListener::LogWriterThread()
|
||||
delete [] logLocal;
|
||||
}
|
||||
|
||||
void ConsoleListener::SendToThread(LogLevel Level, const char *Text)
|
||||
{
|
||||
void ConsoleListener::SendToThread(LogLevel Level, const char *Text) {
|
||||
// Oops, we're already quitting. Just do nothing.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
if (logPendingWritePos_ == (u32)-1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int Len = (int)strlen(Text);
|
||||
if (Len > LOG_PENDING_MAX)
|
||||
@@ -396,8 +312,7 @@ void ConsoleListener::SendToThread(LogLevel Level, const char *Text)
|
||||
|
||||
char ColorAttr[16] = "";
|
||||
int ColorLen = 0;
|
||||
if (bUseColor)
|
||||
{
|
||||
if (useColor_) {
|
||||
// Not ANSI, since the console doesn't support it, but ANSI-like.
|
||||
snprintf(ColorAttr, 16, "\033%d", Level);
|
||||
// For now, rather than properly support it.
|
||||
@@ -406,64 +321,58 @@ void ConsoleListener::SendToThread(LogLevel Level, const char *Text)
|
||||
}
|
||||
|
||||
EnterCriticalSection(&criticalSection);
|
||||
u32 logWritePos = logPendingWritePos.load();
|
||||
u32 logWritePos = logPendingWritePos_.load();
|
||||
u32 prevLogWritePos = logWritePos;
|
||||
if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX)
|
||||
{
|
||||
for (int i = 0; i < ColorLen; ++i)
|
||||
logPending[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i];
|
||||
if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX) {
|
||||
for (int i = 0; i < ColorLen; ++i) {
|
||||
logPending_[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i];
|
||||
}
|
||||
logWritePos += ColorLen;
|
||||
if (logWritePos >= LOG_PENDING_MAX)
|
||||
logWritePos -= LOG_PENDING_MAX;
|
||||
|
||||
int start = 0;
|
||||
if (logWritePos < LOG_PENDING_MAX && logWritePos + Len >= LOG_PENDING_MAX)
|
||||
{
|
||||
if (logWritePos < LOG_PENDING_MAX && logWritePos + Len >= LOG_PENDING_MAX) {
|
||||
const int count = LOG_PENDING_MAX - logWritePos;
|
||||
memcpy(logPending + logWritePos, Text, count);
|
||||
memcpy(logPending_ + logWritePos, Text, count);
|
||||
start = count;
|
||||
logWritePos = 0;
|
||||
}
|
||||
const int count = Len - start;
|
||||
if (count > 0)
|
||||
{
|
||||
memcpy(logPending + logWritePos, Text + start, count);
|
||||
if (count > 0) {
|
||||
memcpy(logPending_ + logWritePos, Text + start, count);
|
||||
logWritePos += count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(logPending + logWritePos, ColorAttr, ColorLen);
|
||||
memcpy(logPending + logWritePos + ColorLen, Text, Len);
|
||||
} else {
|
||||
memcpy(logPending_ + logWritePos, ColorAttr, ColorLen);
|
||||
memcpy(logPending_ + logWritePos + ColorLen, Text, Len);
|
||||
logWritePos += ColorLen + Len;
|
||||
}
|
||||
|
||||
// Oops, we passed the read pos.
|
||||
if (prevLogWritePos < logPendingReadPos && logWritePos >= logPendingReadPos)
|
||||
{
|
||||
char *nextNewline = (char *) memchr(logPending + logWritePos, '\n', LOG_PENDING_MAX - logWritePos);
|
||||
if (prevLogWritePos < logPendingReadPos_ && logWritePos >= logPendingReadPos_) {
|
||||
char *nextNewline = (char *) memchr(logPending_ + logWritePos, '\n', LOG_PENDING_MAX - logWritePos);
|
||||
if (nextNewline == NULL && logWritePos > 0)
|
||||
nextNewline = (char *) memchr(logPending, '\n', logWritePos);
|
||||
nextNewline = (char *) memchr(logPending_, '\n', logWritePos);
|
||||
|
||||
// Okay, have it go right after the next newline.
|
||||
if (nextNewline != NULL)
|
||||
logPendingReadPos = (u32)(nextNewline - logPending + 1);
|
||||
logPendingReadPos_ = (u32)(nextNewline - logPending_ + 1);
|
||||
}
|
||||
|
||||
// Double check we didn't start quitting.
|
||||
if (logPendingWritePos == (u32) -1) {
|
||||
if (logPendingWritePos_ == (u32) -1) {
|
||||
LeaveCriticalSection(&criticalSection);
|
||||
return;
|
||||
}
|
||||
|
||||
logPendingWritePos.store(logWritePos, std::memory_order::memory_order_release);
|
||||
logPendingWritePos_.store(logWritePos, std::memory_order::memory_order_release);
|
||||
LeaveCriticalSection(&criticalSection);
|
||||
|
||||
SetEvent(hTriggerEvent);
|
||||
}
|
||||
|
||||
void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Len)
|
||||
{
|
||||
void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Len) {
|
||||
_dbg_assert_msg_(IsOpen(), "Don't call this before opening the console.");
|
||||
|
||||
/*
|
||||
@@ -499,8 +408,7 @@ void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Le
|
||||
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
break;
|
||||
}
|
||||
if (Len > 10)
|
||||
{
|
||||
if (Len > 10) {
|
||||
// First 10 chars white
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, NULL, NULL);
|
||||
@@ -514,12 +422,9 @@ void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Le
|
||||
MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, tempBuf, wlen);
|
||||
WriteConsole(hConsole, tempBuf, (DWORD)wlen, &cCharsWritten, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize)
|
||||
{
|
||||
void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) {
|
||||
_dbg_assert_msg_(IsOpen(), "Don't call this before opening the console.");
|
||||
#if defined(USING_WIN_UI)
|
||||
// Check size
|
||||
if (Width < 8 || Height < 12) return;
|
||||
|
||||
@@ -546,8 +451,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
|
||||
|
||||
DWORD cAttrRead = ReadBufferSize;
|
||||
DWORD BytesRead = 0;
|
||||
while (BytesRead < BufferSize)
|
||||
{
|
||||
while (BytesRead < BufferSize) {
|
||||
Str.resize(Str.size() + 1);
|
||||
if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead))
|
||||
SLog += StringFromFormat("WriteConsoleOutputCharacter error");
|
||||
@@ -577,8 +481,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
|
||||
|
||||
int BytesWritten = 0;
|
||||
DWORD cAttrWritten = 0;
|
||||
for (size_t i = 0; i < Attr.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < Attr.size(); i++) {
|
||||
if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten))
|
||||
SLog += StringFromFormat("WriteConsoleOutputCharacter error");
|
||||
if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten))
|
||||
@@ -595,67 +498,40 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
|
||||
// if (SLog.length() > 0) Log(LogLevel::LNOTICE, SLog.c_str());
|
||||
|
||||
// Resize the window too
|
||||
if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true);
|
||||
#endif
|
||||
if (Resize) {
|
||||
MoveWindow(GetConsoleWindow(), Left, Top, (Width + 100), Height, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleListener::Log(const LogMessage &msg) {
|
||||
char Text[2048];
|
||||
snprintf(Text, sizeof(Text), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str());
|
||||
Text[sizeof(Text) - 2] = '\n';
|
||||
Text[sizeof(Text) - 1] = '\0';
|
||||
char buf[2048];
|
||||
snprintf(buf, sizeof(buf), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str());
|
||||
buf[sizeof(buf) - 2] = '\n';
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
#if defined(USING_WIN_UI)
|
||||
if (hThread == NULL && IsOpen())
|
||||
WriteToConsole(msg.level, Text, strlen(Text));
|
||||
if (!useThread_ && IsOpen())
|
||||
WriteToConsole(msg.level, buf, strlen(buf));
|
||||
else
|
||||
SendToThread(msg.level, Text);
|
||||
#else
|
||||
char ColorAttr[16] = "";
|
||||
char ResetAttr[16] = "";
|
||||
|
||||
if (bUseColor) {
|
||||
strcpy(ResetAttr, "\033[0m");
|
||||
switch (msg.level) {
|
||||
case LogLevel::LNOTICE: // light green
|
||||
strcpy(ColorAttr, "\033[92m");
|
||||
break;
|
||||
case LogLevel::LERROR: // light red
|
||||
strcpy(ColorAttr, "\033[91m");
|
||||
break;
|
||||
case LogLevel::LWARNING: // light yellow
|
||||
strcpy(ColorAttr, "\033[93m");
|
||||
break;
|
||||
case LogLevel::LINFO: // cyan
|
||||
strcpy(ColorAttr, "\033[96m");
|
||||
break;
|
||||
case LogLevel::LDEBUG: // gray
|
||||
strcpy(ColorAttr, "\033[90m");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr);
|
||||
#endif
|
||||
SendToThread(msg.level, buf);
|
||||
}
|
||||
|
||||
// Clear console screen
|
||||
void ConsoleListener::ClearScreen(bool Cursor)
|
||||
{
|
||||
void ConsoleListener::ClearScreen(bool Cursor) {
|
||||
_dbg_assert_msg_(IsOpen(), "Don't call this before opening the console.");
|
||||
#if defined(USING_WIN_UI)
|
||||
COORD coordScreen = { 0, 0 };
|
||||
DWORD cCharsWritten;
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD dwConSize;
|
||||
|
||||
GetConsoleScreenBufferInfo(hConsole, &csbi);
|
||||
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
||||
DWORD dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
||||
// Write space to the entire console
|
||||
FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
|
||||
DWORD cCharsWritten;
|
||||
COORD coordScreen = { 0, 0 };
|
||||
FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
|
||||
GetConsoleScreenBufferInfo(hConsole, &csbi);
|
||||
FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
|
||||
// Reset cursor
|
||||
if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen);
|
||||
#endif
|
||||
if (Cursor) {
|
||||
SetConsoleCursorPosition(hConsole, coordScreen);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PPSSPP_PLATFORM(WINDOWS)
|
||||
@@ -17,20 +17,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// Windows-only.
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include "LogManager.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "CommonWindows.h"
|
||||
#endif
|
||||
#include "Common/Log/LogManager.h"
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
class ConsoleListener : public LogListener {
|
||||
public:
|
||||
ConsoleListener();
|
||||
~ConsoleListener();
|
||||
|
||||
void Init(bool AutoOpen = true, int Width = 200, int Height = 100, const char * Name = "DebugConsole (PPSSPP)");
|
||||
void Init(bool AutoOpen = true, int Width = 200, int Height = 100);
|
||||
void Open();
|
||||
void UpdateHandle();
|
||||
void Close();
|
||||
@@ -38,38 +42,35 @@ public:
|
||||
void LetterSpace(int Width, int Height);
|
||||
void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst);
|
||||
void PixelSpace(int Left, int Top, int Width, int Height, bool);
|
||||
#if defined(USING_WIN_UI)
|
||||
COORD GetCoordinates(int BytesRead, int BufferWidth);
|
||||
#endif
|
||||
void Log(const LogMessage &message) override;
|
||||
void ClearScreen(bool Cursor = true);
|
||||
|
||||
void Show(bool bShow);
|
||||
bool Hidden() const { return bHidden; }
|
||||
bool Hidden() const { return hidden_; }
|
||||
|
||||
private:
|
||||
#if defined(USING_WIN_UI)
|
||||
HWND hWnd;
|
||||
HANDLE hConsole;
|
||||
HWND hWnd = nullptr;
|
||||
HANDLE hConsole = nullptr;
|
||||
|
||||
static unsigned int WINAPI RunThread(void *lpParam);
|
||||
void LogWriterThread();
|
||||
void SendToThread(LogLevel Level, const char *Text);
|
||||
void WriteToConsole(LogLevel Level, const char *Text, size_t Len);
|
||||
|
||||
static int refCount;
|
||||
static HANDLE hThread;
|
||||
static HANDLE hTriggerEvent;
|
||||
static CRITICAL_SECTION criticalSection;
|
||||
std::thread thread_;
|
||||
|
||||
static char *logPending;
|
||||
static std::atomic<uint32_t> logPendingReadPos;
|
||||
static std::atomic<uint32_t> logPendingWritePos;
|
||||
HANDLE hTriggerEvent = nullptr;
|
||||
CRITICAL_SECTION criticalSection{};
|
||||
|
||||
char *logPending_ = nullptr;
|
||||
std::atomic<uint32_t> logPendingReadPos_;
|
||||
std::atomic<uint32_t> logPendingWritePos_;
|
||||
|
||||
int openWidth_ = 0;
|
||||
int openHeight_ = 0;
|
||||
std::wstring title_;
|
||||
#endif
|
||||
bool bHidden;
|
||||
bool bUseColor;
|
||||
bool hidden_ = false;
|
||||
bool useColor_ = true;
|
||||
bool useThread_ = true;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -28,8 +28,13 @@
|
||||
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
|
||||
#include "Common/LogManager.h"
|
||||
#include "Common/ConsoleListener.h"
|
||||
#include "Common/Log/LogManager.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
#include "Common/Log/ConsoleListener.h"
|
||||
#endif
|
||||
|
||||
#include "Common/Log/StdioListener.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/StringUtils.h"
|
||||
@@ -47,14 +52,14 @@ static const char level_to_char[8] = "-NEWIDV";
|
||||
#define LOG_MSC_OUTPUTDEBUG false
|
||||
#endif
|
||||
|
||||
void GenericLog(LogLevel level, LogType type, const char *file, int line, const char* fmt, ...) {
|
||||
void GenericLog(LogLevel level, Log type, const char *file, int line, const char* fmt, ...) {
|
||||
if (g_bLogEnabledSetting && !(*g_bLogEnabledSetting))
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
LogManager *instance = LogManager::GetInstance();
|
||||
if (instance) {
|
||||
instance->Log(level, type, file, line, fmt, args);
|
||||
instance->LogLine(level, type, file, line, fmt, args);
|
||||
} else {
|
||||
// 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)
|
||||
@@ -69,7 +74,7 @@ void GenericLog(LogLevel level, LogType type, const char *file, int line, const
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
bool GenericLogEnabled(LogLevel level, LogType type) {
|
||||
bool GenericLogEnabled(LogLevel level, Log type) {
|
||||
if (LogManager::GetInstance())
|
||||
return (*g_bLogEnabledSetting) && LogManager::GetInstance()->IsEnabled(level, type);
|
||||
return false;
|
||||
@@ -77,7 +82,7 @@ bool GenericLogEnabled(LogLevel level, LogType type) {
|
||||
|
||||
LogManager *LogManager::logManager_ = NULL;
|
||||
|
||||
// NOTE: Needs to be kept in sync with the LogType enum.
|
||||
// NOTE: Needs to be kept in sync with the Log enum.
|
||||
static const char * const g_logTypeNames[] = {
|
||||
"SYSTEM",
|
||||
"BOOT",
|
||||
@@ -118,7 +123,7 @@ static const char * const g_logTypeNames[] = {
|
||||
LogManager::LogManager(bool *enabledSetting) {
|
||||
g_bLogEnabledSetting = enabledSetting;
|
||||
|
||||
_dbg_assert_(ARRAY_SIZE(g_logTypeNames) == (size_t)LogType::NUMBER_OF_LOGS);
|
||||
_dbg_assert_(ARRAY_SIZE(g_logTypeNames) == (size_t)Log::NUMBER_OF_LOGS);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(g_logTypeNames); i++) {
|
||||
truncate_cpy(log_[i].m_shortName, g_logTypeNames[i]);
|
||||
@@ -137,10 +142,14 @@ LogManager::LogManager(bool *enabledSetting) {
|
||||
#else
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
fileLog_ = new FileLogListener("");
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
consoleLog_ = new ConsoleListener();
|
||||
#ifdef _WIN32
|
||||
#endif
|
||||
if (IsDebuggerPresent())
|
||||
debuggerLog_ = new OutputDebugStringLogListener();
|
||||
#else
|
||||
stdioLog_ = new StdioListener();
|
||||
#endif
|
||||
#endif
|
||||
ringLog_ = new RingbufferLogListener();
|
||||
@@ -148,7 +157,13 @@ LogManager::LogManager(bool *enabledSetting) {
|
||||
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
AddListener(fileLog_);
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
AddListener(consoleLog_);
|
||||
#endif
|
||||
#else
|
||||
AddListener(stdioLog_);
|
||||
#endif
|
||||
#if defined(_MSC_VER) && (defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP))
|
||||
if (IsDebuggerPresent() && debuggerLog_ && LOG_MSC_OUTPUTDEBUG)
|
||||
AddListener(debuggerLog_);
|
||||
@@ -158,10 +173,13 @@ LogManager::LogManager(bool *enabledSetting) {
|
||||
}
|
||||
|
||||
LogManager::~LogManager() {
|
||||
for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; ++i) {
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; ++i) {
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
RemoveListener(fileLog_);
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
RemoveListener(consoleLog_);
|
||||
#endif
|
||||
RemoveListener(stdioLog_);
|
||||
#if defined(_MSC_VER) && defined(USING_WIN_UI)
|
||||
RemoveListener(debuggerLog_);
|
||||
#endif
|
||||
@@ -174,7 +192,10 @@ LogManager::~LogManager() {
|
||||
if (fileLog_)
|
||||
delete fileLog_;
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
delete consoleLog_;
|
||||
#endif
|
||||
delete stdioLog_;
|
||||
delete debuggerLog_;
|
||||
#endif
|
||||
delete ringLog_;
|
||||
@@ -194,14 +215,14 @@ void LogManager::ChangeFileLog(const char *filename) {
|
||||
}
|
||||
|
||||
void LogManager::SaveConfig(Section *section) {
|
||||
for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; i++) {
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) {
|
||||
section->Set((std::string(log_[i].m_shortName) + "Enabled").c_str(), log_[i].enabled);
|
||||
section->Set((std::string(log_[i].m_shortName) + "Level").c_str(), (int)log_[i].level);
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::LoadConfig(const Section *section, bool debugDefaults) {
|
||||
for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; i++) {
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) {
|
||||
bool enabled = false;
|
||||
int level = 0;
|
||||
section->Get((std::string(log_[i].m_shortName) + "Enabled").c_str(), &enabled, true);
|
||||
@@ -211,7 +232,7 @@ void LogManager::LoadConfig(const Section *section, bool debugDefaults) {
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::Log(LogLevel level, LogType type, const char *file, int line, const char *format, va_list args) {
|
||||
void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, const char *format, va_list args) {
|
||||
const LogChannel &log = log_[(size_t)type];
|
||||
if (level > log.level || !log.enabled)
|
||||
return;
|
||||
@@ -234,7 +255,7 @@ void LogManager::Log(LogLevel level, LogType type, const char *file, int line, c
|
||||
file = fileshort + 1;
|
||||
}
|
||||
|
||||
GetTimeFormatted(message.timestamp);
|
||||
GetCurrentTimeFormatted(message.timestamp);
|
||||
|
||||
if (hleCurrentThreadName) {
|
||||
snprintf(message.header, sizeof(message.header), "%-12.12s %c[%s]: %s:%d",
|
||||
@@ -268,7 +289,7 @@ void LogManager::Log(LogLevel level, LogType type, const char *file, int line, c
|
||||
}
|
||||
}
|
||||
|
||||
bool LogManager::IsEnabled(LogLevel level, LogType type) {
|
||||
bool LogManager::IsEnabled(LogLevel level, Log type) {
|
||||
LogChannel &log = log_[(size_t)type];
|
||||
if (level > log.level || !log.enabled)
|
||||
return false;
|
||||
@@ -356,7 +377,7 @@ void OutputDebugStringUTF8(const char *p) {
|
||||
#else
|
||||
|
||||
void OutputDebugStringUTF8(const char *p) {
|
||||
INFO_LOG(SYSTEM, "%s", p);
|
||||
INFO_LOG(Log::System, "%s", p);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -104,6 +104,7 @@ struct LogChannel {
|
||||
};
|
||||
|
||||
class ConsoleListener;
|
||||
class StdioListener;
|
||||
|
||||
class LogManager {
|
||||
private:
|
||||
@@ -114,9 +115,12 @@ private:
|
||||
LogManager(const LogManager &) = delete;
|
||||
void operator=(const LogManager &) = delete;
|
||||
|
||||
LogChannel log_[(size_t)LogType::NUMBER_OF_LOGS];
|
||||
LogChannel log_[(size_t)Log::NUMBER_OF_LOGS];
|
||||
FileLogListener *fileLog_ = nullptr;
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
ConsoleListener *consoleLog_ = nullptr;
|
||||
#endif
|
||||
StdioListener *stdioLog_ = nullptr;
|
||||
OutputDebugStringLogListener *debuggerLog_ = nullptr;
|
||||
RingbufferLogListener *ringLog_ = nullptr;
|
||||
static LogManager *logManager_; // Singleton. Ugh.
|
||||
@@ -129,37 +133,43 @@ public:
|
||||
void RemoveListener(LogListener *listener);
|
||||
|
||||
static u32 GetMaxLevel() { return (u32)MAX_LOGLEVEL; }
|
||||
static int GetNumChannels() { return (int)LogType::NUMBER_OF_LOGS; }
|
||||
static int GetNumChannels() { return (int)Log::NUMBER_OF_LOGS; }
|
||||
|
||||
void Log(LogLevel level, LogType type,
|
||||
const char *file, int line, const char *fmt, va_list args);
|
||||
bool IsEnabled(LogLevel level, LogType type);
|
||||
void LogLine(LogLevel level, Log type,
|
||||
const char *file, int line, const char *fmt, va_list args);
|
||||
bool IsEnabled(LogLevel level, Log type);
|
||||
|
||||
LogChannel *GetLogChannel(LogType type) {
|
||||
LogChannel *GetLogChannel(Log type) {
|
||||
return &log_[(size_t)type];
|
||||
}
|
||||
|
||||
void SetLogLevel(LogType type, LogLevel level) {
|
||||
void SetLogLevel(Log type, LogLevel level) {
|
||||
log_[(size_t)type].level = level;
|
||||
}
|
||||
|
||||
void SetAllLogLevels(LogLevel level) {
|
||||
for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; ++i) {
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; ++i) {
|
||||
log_[i].level = level;
|
||||
}
|
||||
}
|
||||
|
||||
void SetEnabled(LogType type, bool enable) {
|
||||
void SetEnabled(Log type, bool enable) {
|
||||
log_[(size_t)type].enabled = enable;
|
||||
}
|
||||
|
||||
LogLevel GetLogLevel(LogType type) {
|
||||
LogLevel GetLogLevel(Log type) {
|
||||
return log_[(size_t)type].level;
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
ConsoleListener *GetConsoleListener() const {
|
||||
return consoleLog_;
|
||||
}
|
||||
#endif
|
||||
|
||||
StdioListener *GetStdioListener() const {
|
||||
return stdioLog_;
|
||||
}
|
||||
|
||||
OutputDebugStringLogListener *GetDebuggerListener() const {
|
||||
return debuggerLog_;
|
||||
Loaded 100 of 833 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user