Merge branch 'master' into fix-core-gpu-always-true

This commit is contained in:
Henrik Rydgård authored and GitHub committed 2024-09-17 13:03:26 +02:00
commit ed8f0c560a
833 files changed
+41498 -19840

No files matched your search

+4
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
+3 -3
View File
@@ -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
+2
View File
@@ -136,6 +136,8 @@ build
libretro/obj/local
ppsspp_retroachievements.dat
RACache
RAPrefs_PPSSPP.cfg
# For CLion
cmake-build-*/
+2
View File
@@ -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
View File
@@ -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
+16
View File
@@ -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}"
}
]
}
+23
View File
@@ -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
View File
@@ -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()
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+28
View File
@@ -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
}
+2
View File
@@ -161,3 +161,5 @@ private:
};
extern CPUInfo cpu_info;
const char *GetCompilerABI();
+1 -1
View File
@@ -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
View File
@@ -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">
+101 -4
View File
@@ -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>
+1
View File
@@ -7,6 +7,7 @@
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include "Common/Log.h"
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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 {
+14 -12
View File
@@ -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) {
+3 -3
View File
@@ -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;
}
+2 -2
View File
@@ -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) {
+2 -1
View File
@@ -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_; }
+27 -36
View File
@@ -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) {
+32 -63
View File
@@ -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);
};
+4 -4
View File
@@ -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;
}
+3 -3
View File
@@ -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;
}
+5 -5
View File
@@ -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;
}
+9 -9
View File
@@ -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;
+3 -3
View File
@@ -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 {
+7 -2
View File
@@ -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
View File
@@ -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);
}
}
+11 -8
View File
@@ -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)) {
+6 -3
View File
@@ -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_;
+7 -7
View File
@@ -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() { }
+5 -5
View File
@@ -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)
+5 -5
View File
@@ -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 "";
+4
View File
@@ -67,6 +67,10 @@ public:
return root.empty() ? file : root;
}
const std::string &Provider() const {
return provider;
}
bool IsTreeURI() const {
return !root.empty();
}
+12 -6
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+3 -3
View File
@@ -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
View File
@@ -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
+6
View 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();
+4 -1
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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"
+10 -6
View File
@@ -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
View File
@@ -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;
}
+7 -7
View File
@@ -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;
+6 -4
View File
@@ -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;
}
}
+15 -13
View File
@@ -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);
+1 -1
View File
@@ -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;
+12 -12
View File
@@ -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;
+1 -1
View File
@@ -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_);
+38 -83
View File
@@ -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);
+1 -1
View File
@@ -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;
+18 -9
View File
@@ -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;
}
+2 -1
View File
@@ -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.
+12 -12
View File
@@ -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;
}
+20 -17
View File
@@ -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;
}
+1 -1
View File
@@ -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();
+116 -39
View File
@@ -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);
}
+7 -8
View File
@@ -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
View File
@@ -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 =
+20 -7
View File
@@ -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);
+3 -10
View File
@@ -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
+2 -2
View File
@@ -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;
}
+10 -9
View File
@@ -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) {
+3 -3
View File
@@ -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);
}
+7 -7
View File
@@ -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;
+1 -1
View File
@@ -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.
+93 -55
View File
@@ -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 -8
View File
@@ -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);
+2 -2
View File
@@ -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 {
+3 -3
View File
@@ -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();
+121 -394
View File
@@ -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, &region);
// 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);
}
+5 -6
View File
@@ -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_;
+57 -31
View File
@@ -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
}
+7
View File
@@ -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];
+36 -20
View File
@@ -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));
+2 -2
View File
@@ -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
View File
@@ -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_;
-1
View File
@@ -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:
-1
View File
@@ -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,
-13
View File
@@ -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
View File
@@ -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
View File
@@ -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
+20 -10
View File
@@ -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