mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
# Conflicts: # Core/Compatibility.cpp # Core/Compatibility.h # Core/Config.cpp # Core/Config.h # Core/CoreTiming.cpp # Core/HLE/sceDisplay.cpp # GPU/Common/DrawEngineCommon.h # GPU/Common/SplineCommon.cpp # GPU/D3D11/DrawEngineD3D11.cpp # GPU/D3D11/ShaderManagerD3D11.cpp # GPU/Directx9/ShaderManagerDX9.cpp # GPU/Directx9/VertexShaderGeneratorDX9.cpp # GPU/GLES/DrawEngineGLES.cpp # GPU/GPUCommon.cpp # GPU/Vulkan/DrawEngineVulkan.cpp # UI/CwCheatScreen.cpp # UI/EmuScreen.cpp # UI/GameSettingsScreen.cpp # UI/MainScreen.cpp # Windows/GEDebugger/VertexPreview.cpp # Windows/MainWindowMenu.cpp # Windows/ppsspp.rc # Windows/resource.h # assets/compat.ini # ext/native/thin3d/VulkanRenderManager.cpp # libretro/libretro.cpp
This commit is contained in:
commit
c46de369bb
339 files changed
+8561
-6198
No files matched your search
+1
-1
@@ -65,7 +65,7 @@ desc.txt
|
||||
|
||||
Logs
|
||||
Memstick
|
||||
memstick
|
||||
memstick*
|
||||
Cheats
|
||||
|
||||
/git-version.cpp
|
||||
|
||||
+276
-255
@@ -3,9 +3,9 @@ cmake_minimum_required(VERSION 3.6)
|
||||
project(PPSSPP)
|
||||
|
||||
#This is supposed to work but doesn't!
|
||||
if (NOT ANDROID)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(NOT ANDROID)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
enable_language(ASM)
|
||||
@@ -13,64 +13,60 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||
|
||||
add_definitions(-D__STDC_CONSTANT_MACROS)
|
||||
|
||||
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CLANG ON)
|
||||
message("Clang enabled")
|
||||
set(CLANG ON)
|
||||
message("Clang enabled")
|
||||
endif()
|
||||
|
||||
if(FORCED_CPU)
|
||||
message("Detected CPU (${CMAKE_SYSTEM_PROCESSOR}) overridden as: ${FORCED_CPU}")
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${FORCED_CPU})
|
||||
message("Detected CPU (${CMAKE_SYSTEM_PROCESSOR}) overridden as: ${FORCED_CPU}")
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${FORCED_CPU})
|
||||
endif()
|
||||
|
||||
# Detect CPU from CMAKE configuration. Toolchains should set this up
|
||||
if(CMAKE_SYSTEM_PROCESSOR)
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm")
|
||||
set(ARM ON)
|
||||
if(UNIX AND NOT APPLE)
|
||||
execute_process(COMMAND cat /proc/cpuinfo OUTPUT_VARIABLE OUTSTR)
|
||||
string(FIND "${OUTSTR}" "ODROID-XU" pos)
|
||||
if(NOT (pos LESS 0))
|
||||
add_compile_options(-mfloat-abi=hard -marm -mtune=cortex-a15.cortex-a7 -mcpu=cortex-a15 -fomit-frame-pointer)
|
||||
set(ARM_NO_VULKAN ON)
|
||||
endif()
|
||||
set(ARM_DEVICE ON)
|
||||
if(UNIX AND NOT APPLE)
|
||||
execute_process(COMMAND cat /proc/cpuinfo OUTPUT_VARIABLE OUTSTR)
|
||||
string(FIND "${OUTSTR}" "ODROID-XU" pos)
|
||||
if(NOT (pos LESS 0))
|
||||
add_compile_options(-mfloat-abi=hard -marm -mtune=cortex-a15.cortex-a7 -mcpu=cortex-a15 -fomit-frame-pointer)
|
||||
set(ARM_NO_VULKAN ON)
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^armv7")
|
||||
set(ARMV7 ON)
|
||||
set(ARMV7_DEVICE ON)
|
||||
add_compile_options(-mfpu=neon)
|
||||
# Horrifying workaround for bug in android cmake stuff for asm files
|
||||
if (ANDROID)
|
||||
if(ANDROID)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -target armv7a-none-linux-android")
|
||||
endif()
|
||||
endif()
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch64")
|
||||
set(ARM64 ON)
|
||||
add_definitions(-DARM64)
|
||||
set(ARM64 ON)
|
||||
add_definitions(-DARM64)
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^amd64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^AMD64")
|
||||
set(X86 ON)
|
||||
set(X86_64 ON)
|
||||
set(X86_DEVICE ON)
|
||||
set(X86_64_DEVICE ON)
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86")
|
||||
set(X86 ON)
|
||||
set(X86_DEVICE ON)
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^mips")
|
||||
set(MIPS ON)
|
||||
set(MIPS_DEVICE ON)
|
||||
else()
|
||||
message("Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
message("Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(ccache)
|
||||
|
||||
# Remove soon?
|
||||
set(USE_FFMPEG ON)
|
||||
|
||||
# the libraries in the ffmpeg/ directory are not compatible with mingw
|
||||
if(MINGW AND NOT DEFINED USE_SYSTEM_FFMPEG)
|
||||
set(USE_SYSTEM_FFMPEG ON)
|
||||
endif()
|
||||
|
||||
if(NOT ANDROID AND NOT IOS)
|
||||
if(ARM OR SIMULATOR)
|
||||
if(ARM_DEVICE OR SIMULATOR)
|
||||
set(USING_EGL ON)
|
||||
endif()
|
||||
endif()
|
||||
@@ -93,10 +89,6 @@ if(ANDROID OR WIN32 OR (UNIX AND NOT APPLE AND NOT ARM_NO_VULKAN))
|
||||
set(VULKAN ON)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED HEADLESS)
|
||||
set(HEADLESS OFF)
|
||||
endif()
|
||||
|
||||
if(GOLD)
|
||||
add_definitions(-DGOLD)
|
||||
message("Gold Build")
|
||||
@@ -104,24 +96,19 @@ else()
|
||||
message("Normal Build")
|
||||
endif()
|
||||
|
||||
# Doesn't link on some platforms
|
||||
#if(NOT DEFINED UNITTEST)
|
||||
# set(UNITTEST OFF)
|
||||
#endif()
|
||||
|
||||
# User-editable options (go into CMakeCache.txt)
|
||||
# :: Processors
|
||||
option(ARMV7 "Set to ON if targeting an ARMv7 processor" ${ARMV7})
|
||||
option(ARM "Set to ON if targeting an ARM processor" ${ARM})
|
||||
option(MIPS "Set to ON if targeting a MIPS processor" ${MIPS})
|
||||
option(X86 "Set to ON if targeting an X86 processor" ${X86})
|
||||
option(X86_64 "Set to ON if targeting an X86_64 processor" ${X86_64})
|
||||
option(ARMV7 "Set to ON if targeting an ARMv7 processor" ${ARMV7_DEVICE})
|
||||
option(ARM "Set to ON if targeting an ARM processor" ${ARM_DEVICE})
|
||||
option(MIPS "Set to ON if targeting a MIPS processor" ${MIPS_DEVICE})
|
||||
option(X86 "Set to ON if targeting an X86 processor" ${X86_DEVICE})
|
||||
option(X86_64 "Set to ON if targeting an X86_64 processor" ${X86_64_DEVICE})
|
||||
# :: Environments
|
||||
option(USING_EGL "Set to ON if target environment uses EGL" ${USING_EGL})
|
||||
option(USING_FBDEV "Set to ON if target environment uses fbdev (eg. Pandora)" ${USING_FBDEV})
|
||||
option(USING_GLES2 "Set to ON if target device uses OpenGL ES 2.0" ${USING_GLES2})
|
||||
option(RASPBIAN "Set to ON to workaround threading issues when building for ARMV7 on Raspbian" ${RASPBIAN})
|
||||
option(USING_X11_VULKAN "Set to OFF if target environment doesn't use X11 for Vulkan" ON)
|
||||
option(USE_WAYLAND_WSI "Enable or disable Wayland WSI support for Vulkan" ON)
|
||||
# :: Frontends
|
||||
option(USING_QT_UI "Set to ON if you wish to use the Qt frontend wrapper" ${USING_QT_UI})
|
||||
option(MOBILE_DEVICE "Set to ON when targeting a mobile device" ${MOBILE_DEVICE})
|
||||
@@ -130,11 +117,11 @@ option(UNITTEST "Set to ON to generate the unittest target" ${UNITTEST})
|
||||
option(SIMULATOR "Set to ON when targeting an x86 simulator of an ARM platform" ${SIMULATOR})
|
||||
option(LIBRETRO "Set to ON to generate the libretro target" OFF)
|
||||
# :: Options
|
||||
option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG})
|
||||
option(USE_FFMPEG "Build with FFMPEG support" ON)
|
||||
option(USE_DISCORD "Build with Discord support" ON)
|
||||
option(USE_SYSTEM_SNAPPY "Dynamically link against system snappy" ${USE_SYSTEM_SNAPPY})
|
||||
option(USE_SYSTEM_FFMPEG "Dynamically link against system FFMPEG" ${USE_SYSTEM_FFMPEG})
|
||||
option(USE_SYSTEM_LIBZIP "Dynamically link against system libzip" ${USE_SYSTEM_LIBZIP})
|
||||
option(USE_WAYLAND_WSI "Set to ON to require Wayland support for Vulkan" ${USE_WAYLAND_WSI})
|
||||
option(USE_ADDRESS_SANITIZER "Use Clang memory sanitizer" ${USE_ADDRESS_SANITIZER})
|
||||
|
||||
if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN)
|
||||
@@ -145,13 +132,14 @@ if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN)
|
||||
message("NOT using X11 for Vulkan")
|
||||
endif()
|
||||
# add_definitions(-DVK_USE_PLATFORM_XCB_KHR)
|
||||
find_package(Wayland)
|
||||
if (USE_WAYLAND_WSI AND NOT WAYLAND_FOUND)
|
||||
message(FATAL_ERROR "Could not find libwayland, but USE_WAYLAND_WSI was enabled. Failing.")
|
||||
endif()
|
||||
if (WAYLAND_FOUND)
|
||||
include_directories(${WAYLAND_INCLUDE_DIR})
|
||||
add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR)
|
||||
if(USE_WAYLAND_WSI)
|
||||
find_package(Wayland)
|
||||
if(NOT WAYLAND_FOUND)
|
||||
message(STATUS "Could not find Wayland libraries, disabling Wayland WSI support for Vulkan.")
|
||||
else()
|
||||
include_directories(${WAYLAND_INCLUDE_DIR})
|
||||
add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -182,6 +170,10 @@ if(NOT OPENGL_LIBRARIES AND USING_GLES2)
|
||||
set(OPENGL_LIBRARIES GLESv2 EGL)
|
||||
endif()
|
||||
|
||||
if(NOT OPENGL_LIBRARIES)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif()
|
||||
|
||||
if(USING_EGL)
|
||||
if(NOT EGL_LIBRARIES)
|
||||
set(EGL_LIBRARIES EGL)
|
||||
@@ -189,10 +181,6 @@ if(USING_EGL)
|
||||
set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} ${EGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(NOT OPENGL_LIBRARIES)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(SDL2)
|
||||
include(FindThreads)
|
||||
|
||||
@@ -215,7 +203,7 @@ if(MOBILE_DEVICE)
|
||||
add_definitions(-DMOBILE_DEVICE)
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
@@ -245,10 +233,10 @@ if(ARM64)
|
||||
message("Generating for ARMv8, ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
if(NOT MSVC)
|
||||
if (ANDROID)
|
||||
if(ANDROID)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
|
||||
endif()
|
||||
if (CLANG)
|
||||
if(CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch -Wno-uninitialized")
|
||||
endif()
|
||||
|
||||
@@ -280,7 +268,7 @@ if(NOT MSVC)
|
||||
|
||||
# Don't compile with strict aliasing, we're not 100% aliasing-safe
|
||||
add_compile_options(-fno-strict-aliasing)
|
||||
if (${CMAKE_C_COMPILER_ID} STREQUAL "Intel")
|
||||
if(${CMAKE_C_COMPILER_ID} STREQUAL "Intel")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -parallel -fopenmp")
|
||||
else()
|
||||
add_compile_options(-ffast-math)
|
||||
@@ -304,7 +292,7 @@ if(NOT MSVC)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
elseif(NOT ANDROID)
|
||||
# TODO: See if we can get rid of no-psabi
|
||||
if (NOT ${CMAKE_C_COMPILER_ID} STREQUAL "Intel" AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
if(NOT ${CMAKE_C_COMPILER_ID} STREQUAL "Intel" AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
add_definitions(-Wno-psabi)
|
||||
endif()
|
||||
add_definitions(-D_XOPEN_SOURCE=700)
|
||||
@@ -359,14 +347,16 @@ set(CommonX86
|
||||
Common/x64Analyzer.cpp
|
||||
Common/x64Analyzer.h
|
||||
Common/x64Emitter.cpp
|
||||
Common/x64Emitter.h)
|
||||
Common/x64Emitter.h
|
||||
)
|
||||
source_group(x86 FILES ${CommonX86})
|
||||
|
||||
set(CommonARM
|
||||
Common/ArmCPUDetect.cpp
|
||||
Common/ArmEmitter.h
|
||||
Common/ArmEmitter.cpp
|
||||
Common/ColorConvNEON.cpp)
|
||||
Common/ColorConvNEON.cpp
|
||||
)
|
||||
source_group(ARM FILES ${CommonARM})
|
||||
|
||||
set(CommonARM64
|
||||
@@ -374,30 +364,32 @@ set(CommonARM64
|
||||
Common/Arm64Emitter.cpp
|
||||
Common/ArmEmitter.h
|
||||
Common/ArmEmitter.cpp
|
||||
Core/Util/DisArm64.cpp)
|
||||
Core/Util/DisArm64.cpp
|
||||
)
|
||||
source_group(ARM64 FILES ${CommonARM64})
|
||||
|
||||
set(CommonMIPS
|
||||
Common/MipsCPUDetect.cpp
|
||||
Common/MipsEmitter.cpp
|
||||
Common/MipsEmitter.h)
|
||||
Common/MipsEmitter.h
|
||||
)
|
||||
source_group(MIPS FILES ${CommonMIPS})
|
||||
|
||||
if(NOT (X86 OR ARM OR MIPS))
|
||||
set(CommonFake
|
||||
Common/FakeCPUDetect.cpp
|
||||
Common/FakeEmitter.h)
|
||||
Common/FakeEmitter.h
|
||||
)
|
||||
source_group(Fake FILES ${CommonFake})
|
||||
endif()
|
||||
|
||||
set(CommonWindows
|
||||
Common/stdafx.cpp
|
||||
Common/stdafx.h)
|
||||
Common/stdafx.h
|
||||
)
|
||||
source_group(Windows FILES ${CommonWindows})
|
||||
|
||||
set(CommonVulkan ${CommonExtra}
|
||||
Common/Vulkan/SPIRVDisasm.cpp
|
||||
Common/Vulkan/SPIRVDisasm.h
|
||||
Common/Vulkan/VulkanContext.cpp
|
||||
Common/Vulkan/VulkanContext.h
|
||||
Common/Vulkan/VulkanDebug.cpp
|
||||
@@ -407,7 +399,8 @@ set(CommonVulkan ${CommonExtra}
|
||||
Common/Vulkan/VulkanLoader.cpp
|
||||
Common/Vulkan/VulkanLoader.h
|
||||
Common/Vulkan/VulkanMemory.cpp
|
||||
Common/Vulkan/VulkanMemory.h)
|
||||
Common/Vulkan/VulkanMemory.h
|
||||
)
|
||||
|
||||
add_library(Common STATIC
|
||||
${CommonX86}
|
||||
@@ -454,7 +447,8 @@ add_library(Common STATIC
|
||||
Common/ThreadPools.h
|
||||
Common/ThreadSafeList.h
|
||||
Common/Timer.cpp
|
||||
Common/Timer.h)
|
||||
Common/Timer.h
|
||||
)
|
||||
|
||||
add_subdirectory(ext)
|
||||
|
||||
@@ -480,7 +474,7 @@ if(TARGET SDL2::SDL2)
|
||||
target_link_libraries(Common SDL2::SDL2)
|
||||
endif()
|
||||
|
||||
if(USING_GLES2)
|
||||
if(USING_GLES2 OR (USING_EGL AND NOT USING_FBDEV))
|
||||
find_package(X11)
|
||||
endif()
|
||||
|
||||
@@ -491,56 +485,57 @@ add_library(gason STATIC
|
||||
|
||||
add_library(rg_etc1 STATIC
|
||||
ext/native/ext/rg_etc1/rg_etc1.cpp
|
||||
ext/native/ext/rg_etc1/rg_etc1.h)
|
||||
ext/native/ext/rg_etc1/rg_etc1.h
|
||||
)
|
||||
include_directories(ext/native/ext/rg_etc1)
|
||||
|
||||
if(USE_FFMPEG)
|
||||
if(NOT FFMPEG_DIR)
|
||||
if(NOT USE_SYSTEM_FFMPEG)
|
||||
if(ANDROID)
|
||||
if(ARMV7)
|
||||
set(PLATFORM_ARCH "android/armv7")
|
||||
elseif(ARM64)
|
||||
set(PLATFORM_ARCH "android/arm64")
|
||||
elseif(X86_64)
|
||||
set(PLATFORM_ARCH "android/x86_64")
|
||||
elseif(X86)
|
||||
set(PLATFORM_ARCH "android/x86")
|
||||
endif()
|
||||
elseif(IOS)
|
||||
set(PLATFORM_ARCH "ios/universal")
|
||||
elseif(MACOSX)
|
||||
set(PLATFORM_ARCH "macosx/x86_64")
|
||||
elseif(LINUX)
|
||||
if(ARMV7)
|
||||
set(PLATFORM_ARCH "linux/armv7")
|
||||
elseif(ARM64)
|
||||
set(PLATFORM_ARCH "linux/aarch64")
|
||||
elseif(ARM)
|
||||
set(PLATFORM_ARCH "linux/arm")
|
||||
elseif(MIPS)
|
||||
set(PLATFORM_ARCH "linux/mips32")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(PLATFORM_ARCH "linux/x86_64")
|
||||
elseif(X86)
|
||||
set(PLATFORM_ARCH "linux/x86")
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
if(X86_64)
|
||||
set(PLATFORM_ARCH "Windows/x86_64")
|
||||
elseif(X86)
|
||||
set(PLATFORM_ARCH "Windows/x86")
|
||||
endif()
|
||||
endif()
|
||||
if(PLATFORM_ARCH)
|
||||
set(FFMPEG_DIR "ffmpeg/${PLATFORM_ARCH}")
|
||||
else()
|
||||
message("Couldn't find an internal FFmpeg build, using system FFmpeg instead")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if(NOT FFMPEG_DIR)
|
||||
if(NOT USE_SYSTEM_FFMPEG)
|
||||
if(ANDROID)
|
||||
if(ARMV7)
|
||||
set(PLATFORM_ARCH "android/armv7")
|
||||
elseif(ARM64)
|
||||
set(PLATFORM_ARCH "android/arm64")
|
||||
elseif(X86_64)
|
||||
set(PLATFORM_ARCH "android/x86_64")
|
||||
elseif(X86)
|
||||
set(PLATFORM_ARCH "android/x86")
|
||||
endif()
|
||||
elseif(IOS)
|
||||
set(PLATFORM_ARCH "ios/universal")
|
||||
elseif(MACOSX)
|
||||
set(PLATFORM_ARCH "macosx/x86_64")
|
||||
elseif(LINUX)
|
||||
if(ARMV7)
|
||||
set(PLATFORM_ARCH "linux/armv7")
|
||||
elseif(ARM64)
|
||||
set(PLATFORM_ARCH "linux/aarch64")
|
||||
elseif(ARM)
|
||||
set(PLATFORM_ARCH "linux/arm")
|
||||
elseif(MIPS)
|
||||
set(PLATFORM_ARCH "linux/mips32")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(PLATFORM_ARCH "linux/x86_64")
|
||||
elseif(X86)
|
||||
set(PLATFORM_ARCH "linux/x86")
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
if(X86_64)
|
||||
set(PLATFORM_ARCH "Windows/x86_64")
|
||||
elseif(X86)
|
||||
set(PLATFORM_ARCH "Windows/x86")
|
||||
endif()
|
||||
endif()
|
||||
if(PLATFORM_ARCH)
|
||||
set(FFMPEG_DIR "ffmpeg/${PLATFORM_ARCH}")
|
||||
else()
|
||||
message("Couldn't find an internal FFmpeg build, using system FFmpeg instead")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(FFmpeg REQUIRED avcodec avformat avutil swresample swscale)
|
||||
find_package(FFmpeg REQUIRED avcodec avformat avutil swresample swscale)
|
||||
endif(USE_FFMPEG)
|
||||
|
||||
find_package(ZLIB)
|
||||
@@ -588,7 +583,7 @@ add_library(cityhash STATIC
|
||||
)
|
||||
include_directories(ext/cityhash)
|
||||
|
||||
if (NOT MSVC)
|
||||
if(NOT MSVC)
|
||||
# These can be fast even for debug.
|
||||
set_target_properties(udis86 PROPERTIES COMPILE_FLAGS "-O3")
|
||||
set_target_properties(cityhash PROPERTIES COMPILE_FLAGS "-O3")
|
||||
@@ -657,7 +652,8 @@ else()
|
||||
ext/native/ext/libzip/zip_unchange.c
|
||||
ext/native/ext/libzip/zip_unchange_all.c
|
||||
ext/native/ext/libzip/zip_unchange_archive.c
|
||||
ext/native/ext/libzip/zip_unchange_data.c)
|
||||
ext/native/ext/libzip/zip_unchange_data.c
|
||||
)
|
||||
target_link_libraries(libzip)
|
||||
include_directories(ext/native/ext/libzip)
|
||||
set(LIBZIP_LIBRARY libzip)
|
||||
@@ -668,15 +664,15 @@ find_path(PNG_PNG_INCLUDE_DIR NAMES "libpng17/png.h")
|
||||
find_library(PNG_LIBRARY NAMES png17 libpng17)
|
||||
find_package(PackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PNG REQUIRED_VARS PNG_LIBRARY PNG_PNG_INCLUDE_DIR)
|
||||
if (PNG_FOUND)
|
||||
if(PNG_FOUND)
|
||||
include_directories(${PNG_PNG_INCLUDE_DIR})
|
||||
else()
|
||||
if(ARM)
|
||||
set(PNG_ARM_INCLUDES
|
||||
ext/native/ext/libpng17/arm/arm_init.c
|
||||
ext/native/ext/libpng17/arm/filter_neon.S
|
||||
ext/native/ext/libpng17/arm/filter_neon_intrinsics.c
|
||||
)
|
||||
ext/native/ext/libpng17/arm/arm_init.c
|
||||
ext/native/ext/libpng17/arm/filter_neon.S
|
||||
ext/native/ext/libpng17/arm/filter_neon_intrinsics.c
|
||||
)
|
||||
endif()
|
||||
add_library(png17 STATIC
|
||||
ext/native/ext/libpng17/pngconf.h
|
||||
@@ -701,7 +697,8 @@ else()
|
||||
ext/native/ext/libpng17/pngwrite.c
|
||||
ext/native/ext/libpng17/pngwtran.c
|
||||
ext/native/ext/libpng17/pngwutil.c
|
||||
${PNG_ARM_INCLUDES} )
|
||||
${PNG_ARM_INCLUDES}
|
||||
)
|
||||
set(PNG_LIBRARY png17)
|
||||
include_directories(ext/native/ext)
|
||||
endif()
|
||||
@@ -710,13 +707,14 @@ set(nativeExtra)
|
||||
set(nativeExtraLibs)
|
||||
|
||||
if(ANDROID)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
Common/GL/GLInterface/EGLAndroid.cpp
|
||||
Common/GL/GLInterface/EGLAndroid.h
|
||||
Common/GL/GLInterface/EGL.cpp
|
||||
Common/GL/GLInterface/EGL.h
|
||||
Common/GL/GLInterface/GLInterface.cpp
|
||||
Common/GL/GLInterfaceBase.h)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
Common/GL/GLInterface/EGLAndroid.cpp
|
||||
Common/GL/GLInterface/EGLAndroid.h
|
||||
Common/GL/GLInterface/EGL.cpp
|
||||
Common/GL/GLInterface/EGL.h
|
||||
Common/GL/GLInterface/GLInterface.cpp
|
||||
Common/GL/GLInterfaceBase.h
|
||||
)
|
||||
|
||||
set(nativeExtra ${nativeExtra}
|
||||
ext/native/base/NativeApp.h
|
||||
@@ -731,7 +729,8 @@ if(ANDROID)
|
||||
android/jni/native_audio.cpp
|
||||
android/jni/native_audio.h
|
||||
android/jni/native-audio-so.cpp
|
||||
android/jni/native-audio-so.h)
|
||||
android/jni/native-audio-so.h
|
||||
)
|
||||
# No target
|
||||
elseif(IOS)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
@@ -750,7 +749,8 @@ elseif(IOS)
|
||||
ios/SubtleVolume.mm
|
||||
ios/iCade/iCadeReaderView.h
|
||||
ios/iCade/iCadeReaderView.m
|
||||
ios/iCade/iCadeState.h)
|
||||
ios/iCade/iCadeState.h
|
||||
)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation")
|
||||
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
|
||||
@@ -770,34 +770,38 @@ elseif(IOS)
|
||||
|
||||
set(TargetBin PPSSPP)
|
||||
elseif(USING_QT_UI)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
find_package(Qt5 COMPONENTS OpenGL Gui Core)
|
||||
if(NOT SDL2_FOUND)
|
||||
find_package(Qt5 COMPONENTS Multimedia)
|
||||
endif(NOT SDL2_FOUND)
|
||||
list(APPEND NativeAppSource
|
||||
Qt/QtMain.cpp
|
||||
Qt/QtMain.h
|
||||
Qt/QtHost.cpp
|
||||
Qt/QtHost.h
|
||||
Qt/mainwindow.cpp
|
||||
Qt/mainwindow.h
|
||||
)
|
||||
add_definitions(-DUSING_QT_UI)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
find_package(Qt5 COMPONENTS OpenGL Gui Core)
|
||||
if(NOT SDL2_FOUND)
|
||||
find_package(Qt5 COMPONENTS Multimedia)
|
||||
endif(NOT SDL2_FOUND)
|
||||
list(APPEND NativeAppSource
|
||||
Qt/QtMain.cpp
|
||||
Qt/QtMain.h
|
||||
Qt/QtHost.cpp
|
||||
Qt/QtHost.h
|
||||
Qt/mainwindow.cpp
|
||||
Qt/mainwindow.h
|
||||
)
|
||||
add_definitions(-DUSING_QT_UI)
|
||||
if(USING_GLES2)
|
||||
add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2)
|
||||
endif()
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core)
|
||||
set(TargetBin PPSSPPQt)
|
||||
|
||||
# Enable SDL if found
|
||||
if (SDL2_FOUND)
|
||||
add_definitions(-DSDL)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
SDL/SDLJoystick.h
|
||||
SDL/SDLJoystick.cpp)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
|
||||
else(SDL2_FOUND)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} Qt5::Multimedia)
|
||||
endif()
|
||||
# Enable SDL if found
|
||||
if(SDL2_FOUND)
|
||||
add_definitions(-DSDL)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
SDL/SDLJoystick.h
|
||||
SDL/SDLJoystick.cpp
|
||||
)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
|
||||
else(SDL2_FOUND)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} Qt5::Multimedia)
|
||||
endif()
|
||||
|
||||
elseif(WIN32)
|
||||
# Don't care about SDL.
|
||||
@@ -807,25 +811,26 @@ elseif(WIN32)
|
||||
else()
|
||||
link_directories(dx9sdk/Lib/x86)
|
||||
endif()
|
||||
set(nativeExtra ${nativeExtra} ext/native/base/logging.cpp)
|
||||
set(nativeExtra ${nativeExtra} ext/native/base/logging.cpp)
|
||||
elseif(TARGET SDL2::SDL2)
|
||||
set(TargetBin PPSSPPSDL)
|
||||
# Require SDL
|
||||
add_definitions(-DSDL)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
SDL/SDLJoystick.h
|
||||
SDL/SDLJoystick.cpp
|
||||
SDL/SDLMain.cpp
|
||||
SDL/SDLGLGraphicsContext.cpp
|
||||
SDL/SDLVulkanGraphicsContext.cpp)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
|
||||
if(APPLE)
|
||||
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY})
|
||||
elseif(USING_EGL)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} pthread)
|
||||
endif()
|
||||
set(TargetBin PPSSPPSDL)
|
||||
set(TargetBin PPSSPPSDL)
|
||||
# Require SDL
|
||||
add_definitions(-DSDL)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
SDL/SDLJoystick.h
|
||||
SDL/SDLJoystick.cpp
|
||||
SDL/SDLMain.cpp
|
||||
SDL/SDLGLGraphicsContext.cpp
|
||||
SDL/SDLVulkanGraphicsContext.cpp
|
||||
)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
|
||||
if(APPLE)
|
||||
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY})
|
||||
elseif(USING_EGL)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} pthread)
|
||||
endif()
|
||||
set(TargetBin PPSSPPSDL)
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find SDL2. Failing.")
|
||||
endif()
|
||||
@@ -845,6 +850,7 @@ list(APPEND NativeAppSource
|
||||
UI/PauseScreen.cpp
|
||||
UI/GameScreen.cpp
|
||||
UI/GameSettingsScreen.cpp
|
||||
UI/GPUDriverTestScreen.cpp
|
||||
UI/TiltAnalogSettingsScreen.cpp
|
||||
UI/TiltEventProcessor.cpp
|
||||
UI/TouchControlLayoutScreen.cpp
|
||||
@@ -861,12 +867,13 @@ list(APPEND NativeAppSource
|
||||
UI/ProfilerDraw.cpp
|
||||
UI/ui_atlas.cpp
|
||||
UI/TextureUtil.cpp
|
||||
UI/ComboKeyMappingScreen.cpp)
|
||||
UI/ComboKeyMappingScreen.cpp
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
if (ARM)
|
||||
if(ARM)
|
||||
set(NativeAppSource ${NativeAppSource} android/jni/ArmEmitterTest.cpp)
|
||||
elseif (ARM64)
|
||||
elseif(ARM64)
|
||||
set(NativeAppSource ${NativeAppSource} android/jni/Arm64EmitterTest.cpp)
|
||||
endif()
|
||||
set(nativeExtra ${nativeExtra} ${NativeAppSource})
|
||||
@@ -878,7 +885,8 @@ set(THIN3D_PLATFORMS ext/native/thin3d/thin3d_gl.cpp
|
||||
ext/native/thin3d/GLQueueRunner.cpp
|
||||
ext/native/thin3d/GLQueueRunner.h
|
||||
ext/native/thin3d/DataFormatGL.cpp
|
||||
ext/native/thin3d/DataFormatGL.h)
|
||||
ext/native/thin3d/DataFormatGL.h
|
||||
)
|
||||
|
||||
set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS}
|
||||
ext/native/thin3d/thin3d_vulkan.cpp
|
||||
@@ -886,16 +894,18 @@ set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS}
|
||||
ext/native/thin3d/VulkanRenderManager.h
|
||||
ext/native/thin3d/VulkanQueueRunner.cpp
|
||||
ext/native/thin3d/VulkanQueueRunner.h
|
||||
ext/native/thin3d/DataFormat.h)
|
||||
ext/native/thin3d/DataFormat.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS}
|
||||
ext/native/thin3d/thin3d_d3d9.cpp
|
||||
ext/native/thin3d/thin3d_d3d11.cpp
|
||||
ext/native/thin3d/d3dx9_loader.cpp
|
||||
ext/native/thin3d/d3dx9_loader.h
|
||||
ext/native/thin3d/d3d11_loader.cpp
|
||||
ext/native/thin3d/d3d11_loader.h)
|
||||
set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS}
|
||||
ext/native/thin3d/thin3d_d3d9.cpp
|
||||
ext/native/thin3d/thin3d_d3d11.cpp
|
||||
ext/native/thin3d/d3dx9_loader.cpp
|
||||
ext/native/thin3d/d3dx9_loader.h
|
||||
ext/native/thin3d/d3d11_loader.cpp
|
||||
ext/native/thin3d/d3d11_loader.h
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(native STATIC
|
||||
@@ -1052,21 +1062,22 @@ add_library(native STATIC
|
||||
ext/native/ext/jpge/jpgd.cpp
|
||||
ext/native/ext/jpge/jpgd.h
|
||||
ext/native/ext/jpge/jpge.cpp
|
||||
ext/native/ext/jpge/jpge.h)
|
||||
ext/native/ext/jpge/jpge.h
|
||||
)
|
||||
include_directories(ext/native)
|
||||
|
||||
if (LINUX AND NOT ANDROID)
|
||||
SET(RT_LIB rt)
|
||||
if(LINUX AND NOT ANDROID)
|
||||
set(RT_LIB rt)
|
||||
endif()
|
||||
|
||||
SET(ATOMIC_LIB)
|
||||
set(ATOMIC_LIB)
|
||||
if(ANDROID)
|
||||
SET(ATOMIC_LIB atomic)
|
||||
set(ATOMIC_LIB atomic)
|
||||
endif()
|
||||
|
||||
target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARY} ${ZLIB_LIBRARY} rg_etc1 gason udis86 ${RT_LIB} ${nativeExtraLibs} ${ATOMIC_LIB})
|
||||
if(TARGET Ext::GLEW)
|
||||
target_link_libraries(native Ext::GLEW)
|
||||
target_link_libraries(native Ext::GLEW)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
@@ -1088,7 +1099,8 @@ add_library(kirk STATIC
|
||||
ext/libkirk/bn.c
|
||||
ext/libkirk/ec.c
|
||||
ext/libkirk/kirk_engine.c
|
||||
ext/libkirk/kirk_engine.h)
|
||||
ext/libkirk/kirk_engine.h
|
||||
)
|
||||
include_directories(ext/libkirk)
|
||||
|
||||
add_library(sfmt19937 STATIC
|
||||
@@ -1133,7 +1145,7 @@ set(CoreExtra ${CoreExtra}
|
||||
Core/MIPS/IR/IRPassSimplify.h
|
||||
Core/MIPS/IR/IRRegCache.cpp
|
||||
Core/MIPS/IR/IRRegCache.h
|
||||
)
|
||||
)
|
||||
|
||||
list(APPEND CoreExtra
|
||||
Core/MIPS/ARM/ArmAsm.cpp
|
||||
@@ -1169,7 +1181,8 @@ list(APPEND CoreExtra
|
||||
Core/MIPS/ARM64/Arm64RegCacheFPU.cpp
|
||||
Core/MIPS/ARM64/Arm64RegCacheFPU.h
|
||||
GPU/Common/VertexDecoderArm64.cpp
|
||||
Core/Util/DisArm64.cpp)
|
||||
Core/Util/DisArm64.cpp
|
||||
)
|
||||
|
||||
list(APPEND CoreExtra
|
||||
Core/MIPS/x86/Asm.cpp
|
||||
@@ -1197,17 +1210,19 @@ list(APPEND CoreExtra
|
||||
GPU/Common/VertexDecoderFake.cpp
|
||||
)
|
||||
|
||||
if (NOT MOBILE_DEVICE)
|
||||
if(NOT MOBILE_DEVICE)
|
||||
set(CoreExtra ${CoreExtra}
|
||||
Core/AVIDump.cpp
|
||||
Core/AVIDump.h
|
||||
Core/WaveFile.cpp
|
||||
Core/WaveFile.h)
|
||||
Core/WaveFile.h
|
||||
)
|
||||
endif()
|
||||
|
||||
set(GPU_GLES
|
||||
GPU/GLES/DepalettizeShaderGLES.cpp
|
||||
GPU/GLES/DepalettizeShaderGLES.h
|
||||
GPU/GLES/DepthBufferGLES.cpp
|
||||
GPU/GLES/GPU_GLES.cpp
|
||||
GPU/GLES/GPU_GLES.h
|
||||
GPU/GLES/FragmentShaderGeneratorGLES.cpp
|
||||
@@ -1232,7 +1247,7 @@ set(GPU_GLES
|
||||
)
|
||||
|
||||
set(GPU_VULKAN
|
||||
GPU/Vulkan/DepalettizeShaderVulkan.cpp
|
||||
GPU/Vulkan/DepalettizeShaderVulkan.cpp
|
||||
GPU/Vulkan/DepalettizeShaderVulkan.h
|
||||
GPU/Vulkan/DebugVisVulkan.cpp
|
||||
GPU/Vulkan/DebugVisVulkan.h
|
||||
@@ -1262,7 +1277,7 @@ set(GPU_VULKAN
|
||||
)
|
||||
|
||||
set(GPU_D3D9
|
||||
GPU/Directx9/DepalettizeShaderDX9.cpp
|
||||
GPU/Directx9/DepalettizeShaderDX9.cpp
|
||||
GPU/Directx9/DepalettizeShaderDX9.h
|
||||
GPU/Directx9/DrawEngineDX9.cpp
|
||||
GPU/Directx9/DrawEngineDX9.h
|
||||
@@ -1286,7 +1301,7 @@ set(GPU_D3D9
|
||||
)
|
||||
|
||||
set(GPU_D3D11
|
||||
GPU/D3D11/DepalettizeShaderD3D11.cpp
|
||||
GPU/D3D11/DepalettizeShaderD3D11.cpp
|
||||
GPU/D3D11/DepalettizeShaderD3D11.h
|
||||
GPU/D3D11/DrawEngineD3D11.cpp
|
||||
GPU/D3D11/DrawEngineD3D11.h
|
||||
@@ -1395,7 +1410,8 @@ set(GPU_SOURCES
|
||||
GPU/Software/SoftGpu.h
|
||||
GPU/Software/TransformUnit.cpp
|
||||
GPU/Software/TransformUnit.h
|
||||
GPU/ge_constants.h)
|
||||
GPU/ge_constants.h
|
||||
)
|
||||
|
||||
# 'ppsspp_jni' on ANDROID, 'Core' everywhere else
|
||||
# SHARED on ANDROID, STATIC everywhere else
|
||||
@@ -1733,13 +1749,14 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
${CORE_NEON}
|
||||
${GPU_SOURCES}
|
||||
ext/disarm.cpp
|
||||
git-version.cpp)
|
||||
git-version.cpp
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
set(CoreExtraLibs ${CoreExtraLibs} android)
|
||||
if(X86_64)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic")
|
||||
endif()
|
||||
set(CoreExtraLibs ${CoreExtraLibs} android)
|
||||
if(X86_64)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CoreExtraLibs ${CoreExtraLibs} armips)
|
||||
@@ -1753,27 +1770,28 @@ set(CoreExtraLibs ${CoreExtraLibs} armips)
|
||||
set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-glsl)
|
||||
|
||||
if(WIN32)
|
||||
set(GlslangLibs ${GlslangLibs} spirv-cross-hlsl)
|
||||
set(GlslangLibs ${GlslangLibs} spirv-cross-hlsl)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs}
|
||||
${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||
|
||||
if(FFmpeg_FOUND)
|
||||
target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1)
|
||||
target_link_libraries(${CoreLibName}
|
||||
FFmpeg::avcodec
|
||||
FFmpeg::avformat
|
||||
FFmpeg::avutil
|
||||
FFmpeg::swresample
|
||||
FFmpeg::swscale
|
||||
${ZLIB_LIBRARY}
|
||||
)
|
||||
target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1)
|
||||
target_link_libraries(${CoreLibName}
|
||||
FFmpeg::avcodec
|
||||
FFmpeg::avformat
|
||||
FFmpeg::avutil
|
||||
FFmpeg::swresample
|
||||
FFmpeg::swscale
|
||||
${ZLIB_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
|
||||
# Discord integration
|
||||
if(NOT IOS)
|
||||
target_link_libraries(${CoreLibName} discord-rpc)
|
||||
if(USE_DISCORD AND NOT IOS)
|
||||
add_definitions(-DUSE_DISCORD=1)
|
||||
target_link_libraries(${CoreLibName} discord-rpc)
|
||||
endif()
|
||||
|
||||
setup_target_project(${CoreLibName} Core)
|
||||
@@ -1885,7 +1903,8 @@ set(WindowsFiles
|
||||
Windows/ppsspp.rc
|
||||
Windows/resource.h
|
||||
Windows/stdafx.cpp
|
||||
Windows/stdafx.h)
|
||||
Windows/stdafx.h
|
||||
)
|
||||
|
||||
list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
@@ -1908,7 +1927,10 @@ set(NativeAssets
|
||||
assets/ppge_atlas.zim
|
||||
assets/rargray.png
|
||||
assets/unknown.png
|
||||
assets/zip.png)
|
||||
assets/zip.png
|
||||
source_assets/image/logo.png
|
||||
source_assets/image/icon_regular_72.png
|
||||
)
|
||||
|
||||
|
||||
if(HEADLESS)
|
||||
@@ -1919,9 +1941,9 @@ if(HEADLESS)
|
||||
headless/Compare.cpp
|
||||
headless/Compare.h
|
||||
headless/SDLHeadlessHost.cpp
|
||||
headless/SDLHeadlessHost.h)
|
||||
target_link_libraries(PPSSPPHeadless
|
||||
${COCOA_LIBRARY} ${LinkCommon})
|
||||
headless/SDLHeadlessHost.h
|
||||
)
|
||||
target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${LinkCommon})
|
||||
setup_target_project(PPSSPPHeadless headless)
|
||||
endif()
|
||||
|
||||
@@ -1936,8 +1958,7 @@ if(UNITTEST)
|
||||
Core/MIPS/ARM/ArmRegCache.cpp
|
||||
Core/MIPS/ARM/ArmRegCacheFPU.cpp
|
||||
)
|
||||
target_link_libraries(unitTest
|
||||
${COCOA_LIBRARY} ${LinkCommon} Common)
|
||||
target_link_libraries(unitTest ${COCOA_LIBRARY} ${LinkCommon} Common)
|
||||
setup_target_project(unitTest unittest)
|
||||
endif()
|
||||
|
||||
@@ -1945,12 +1966,12 @@ if(LIBRETRO)
|
||||
add_subdirectory(libretro)
|
||||
endif()
|
||||
|
||||
if (TargetBin)
|
||||
if (IOS OR APPLE)
|
||||
if (APPLE AND NOT IOS)
|
||||
set(ICON_PATH_ABS ${CMAKE_CURRENT_SOURCE_DIR}/icons/ppsspp.icns)
|
||||
set( MACOSX_BUNDLE_ICON_FILE ppsspp.icns )
|
||||
set_source_files_properties(${ICON_PATH_ABS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
if(TargetBin)
|
||||
if(IOS OR APPLE)
|
||||
if(APPLE AND NOT IOS)
|
||||
set(ICON_PATH_ABS ${CMAKE_CURRENT_SOURCE_DIR}/icons/ppsspp.icns)
|
||||
set(MACOSX_BUNDLE_ICON_FILE ppsspp.icns)
|
||||
set_source_files_properties(${ICON_PATH_ABS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
endif()
|
||||
|
||||
# TODO: there must a native way to copy these.
|
||||
@@ -1960,17 +1981,17 @@ if (TargetBin)
|
||||
file(GLOB_RECURSE LANG_FILES assets/lang/*)
|
||||
file(GLOB_RECURSE SHADER_FILES assets/shaders/*)
|
||||
|
||||
if (APPLE AND NOT IOS)
|
||||
set_source_files_properties(${NativeAssets} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets")
|
||||
set_source_files_properties(${FLASH0_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/flash0/font")
|
||||
set_source_files_properties(${LANG_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/lang")
|
||||
set_source_files_properties(${SHADER_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/shaders")
|
||||
if(APPLE AND NOT IOS)
|
||||
set_source_files_properties(${NativeAssets} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets")
|
||||
set_source_files_properties(${FLASH0_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/flash0/font")
|
||||
set_source_files_properties(${LANG_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/lang")
|
||||
set_source_files_properties(${SHADER_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION "MacOS/assets/shaders")
|
||||
endif()
|
||||
|
||||
if (IOS)
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Launch Screen.storyboard")
|
||||
if(IOS)
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Launch Screen.storyboard")
|
||||
else()
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource})
|
||||
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource})
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
add_executable(${TargetBin} WIN32 ${NativeAppSource})
|
||||
@@ -1988,8 +2009,8 @@ endif()
|
||||
|
||||
# installs
|
||||
if(NOT ANDROID)
|
||||
file(INSTALL ${NativeAssets} DESTINATION assets)
|
||||
file(INSTALL assets/flash0 DESTINATION assets)
|
||||
file(INSTALL ${NativeAssets} DESTINATION assets)
|
||||
file(INSTALL assets/flash0 DESTINATION assets)
|
||||
endif()
|
||||
# packaging and code signing
|
||||
if(IOS)
|
||||
@@ -2000,7 +2021,7 @@ if(IOS)
|
||||
file(INSTALL ${IOSAssets} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/assets)
|
||||
file(GLOB IOSAssets ios/assets/Default-568h@*.png)
|
||||
file(INSTALL ${IOSAssets} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if (IOS_DEBUG)
|
||||
if(IOS_DEBUG)
|
||||
file(INSTALL pspautotests DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/assets)
|
||||
endif()
|
||||
set(RSRC_XIB_FILES assets/Icon@2x.png)
|
||||
@@ -2008,11 +2029,11 @@ if(IOS)
|
||||
set_source_files_properties(${RSRC_XIB_FILES}
|
||||
PROPERTIES MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
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()
|
||||
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}\"
|
||||
@@ -2023,8 +2044,8 @@ if(IOS)
|
||||
RESOURCE "ios/Launch Screen.storyboard"
|
||||
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 "-"
|
||||
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE NO
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
|
||||
)
|
||||
endif()
|
||||
@@ -80,6 +80,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -107,6 +108,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -242,7 +244,6 @@
|
||||
<ClInclude Include="ThreadSafeList.h" />
|
||||
<ClInclude Include="Thunk.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="Vulkan\SPIRVDisasm.h" />
|
||||
<ClInclude Include="Vulkan\VulkanContext.h" />
|
||||
<ClInclude Include="Vulkan\VulkanDebug.h" />
|
||||
<ClInclude Include="Vulkan\VulkanImage.h" />
|
||||
@@ -314,7 +315,6 @@
|
||||
<ClCompile Include="ThreadPools.cpp" />
|
||||
<ClCompile Include="Thunk.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="Vulkan\SPIRVDisasm.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanContext.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanDebug.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanImage.cpp" />
|
||||
@@ -331,4 +331,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -58,9 +58,6 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="GraphicsContext.h" />
|
||||
<ClInclude Include="DbgNew.h" />
|
||||
<ClInclude Include="Vulkan\SPIRVDisasm.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vulkan\VulkanLoader.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
@@ -119,9 +116,6 @@
|
||||
<ClCompile Include="GL\GLInterface\GLInterface.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\SPIRVDisasm.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\VulkanLoader.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
@@ -155,4 +149,4 @@
|
||||
<UniqueIdentifier>{c14d66ef-5f7c-4565-975a-72774e7ccfb9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
+18
-16
@@ -30,6 +30,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "CommonWindows.h"
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h> // for SHGetFolderPath
|
||||
#include <shellapi.h>
|
||||
#include <commdlg.h> // for GetSaveFileName
|
||||
@@ -121,7 +122,11 @@ std::string ResolvePath(const std::string &path) {
|
||||
|
||||
std::wstring input = ConvertUTF8ToWString(path);
|
||||
if (getFinalPathNameByHandleW) {
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
HANDLE hFile = CreateFile2(input.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
|
||||
#else
|
||||
HANDLE hFile = CreateFile(input.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
#endif
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
wcscpy_s(buf, BUF_SIZE - 1, input.c_str());
|
||||
} else {
|
||||
@@ -336,7 +341,7 @@ bool CreateFullPath(const std::string &path)
|
||||
return true;
|
||||
}
|
||||
std::string subPath = fullPath.substr(0, position);
|
||||
if (!File::Exists(subPath))
|
||||
if (position != 0 && !File::Exists(subPath))
|
||||
File::CreateDir(subPath);
|
||||
|
||||
// A safety check
|
||||
@@ -647,7 +652,6 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(hFind);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -656,17 +660,16 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
{
|
||||
const std::string virtualName = ConvertWStringToUTF8(ffd.cFileName);
|
||||
#else
|
||||
struct dirent dirent, *result = NULL;
|
||||
struct dirent *result = NULL;
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
if (!dirp)
|
||||
return false;
|
||||
|
||||
// non windows loop
|
||||
while (!readdir_r(dirp, &dirent, &result) && result)
|
||||
while ((result = readdir(dirp)))
|
||||
{
|
||||
const std::string virtualName = result->d_name;
|
||||
#endif
|
||||
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
@@ -678,10 +681,11 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
{
|
||||
if (!DeleteDirRecursively(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
#else
|
||||
FindClose(hFind);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -689,10 +693,11 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
{
|
||||
if (!File::Delete(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
#else
|
||||
FindClose(hFind);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -704,8 +709,7 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
File::DeleteDir(directory);
|
||||
return true;
|
||||
return File::DeleteDir(directory);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -718,13 +722,11 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
if (!File::Exists(source_path)) return;
|
||||
if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
|
||||
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
||||
struct dirent_large diren;
|
||||
struct dirent *result = NULL;
|
||||
DIR *dirp = opendir(source_path.c_str());
|
||||
if (!dirp) return;
|
||||
|
||||
while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
|
||||
while ((result = readdir(dirp)))
|
||||
{
|
||||
const std::string virtualName(result->d_name);
|
||||
// check for "." and ".."
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "OSVersion.h"
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
|
||||
+17
-1
@@ -95,4 +95,20 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
||||
*_pExtension = full_path.substr(fname_end);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetFilenameFromPath(std::string full_path) {
|
||||
size_t pos;
|
||||
#ifdef _WIN32
|
||||
pos = full_path.rfind('\\');
|
||||
if (pos != std::string::npos) {
|
||||
return full_path.substr(pos + 1);
|
||||
}
|
||||
#endif
|
||||
pos = full_path.rfind('/');
|
||||
if (pos != std::string::npos) {
|
||||
return full_path.substr(pos + 1);
|
||||
}
|
||||
// No directory components, just return the full path.
|
||||
return full_path;
|
||||
}
|
||||
@@ -45,3 +45,5 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...)
|
||||
|
||||
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension);
|
||||
|
||||
std::string GetFilenameFromPath(std::string full_path);
|
||||
@@ -1,617 +0,0 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/Vulkan/SPIRVDisasm.h"
|
||||
#include "ext/vulkan/spirv.hpp"
|
||||
|
||||
#define WRITE p+=sprintf
|
||||
|
||||
struct SpirvID {
|
||||
std::string name;
|
||||
int opcode;
|
||||
};
|
||||
|
||||
struct OpInfo {
|
||||
const char *name;
|
||||
const char *extra;
|
||||
};
|
||||
|
||||
static const char *executionModelNames[] = {
|
||||
"Vertex", // 0,
|
||||
"TessellationControl", // 1,
|
||||
"TessellationEvaluation", // 2,
|
||||
"Geometry", // 3,
|
||||
"Fragment", // 4,
|
||||
"GLCompute", // 5,
|
||||
"Kernel", // 6,
|
||||
};
|
||||
|
||||
static const char *storageClassNames[] = {
|
||||
"UniformConstant",
|
||||
"Input",
|
||||
"Uniform",
|
||||
"Output",
|
||||
"Workgroup",
|
||||
"CrossWorkgroup",
|
||||
"Private",
|
||||
"Function",
|
||||
"Generic",
|
||||
"PushConstant",
|
||||
"AtomicCounter",
|
||||
"Image",
|
||||
};
|
||||
|
||||
static const char *decorationNames[] = {
|
||||
"RelaxedPrecision", // 0,
|
||||
"SpecId", // 1,
|
||||
"Block", // 2,
|
||||
"BufferBlock", // 3,
|
||||
"RowMajor", // 4,
|
||||
"ColMajor", // 5,
|
||||
"ArrayStride", // 6,
|
||||
"MatrixStride", // 7,
|
||||
"GLSLShared", // 8,
|
||||
"GLSLPacked", // 9,
|
||||
"CPacked", // 10,
|
||||
"BuiltIn", // 11,
|
||||
nullptr, // 12
|
||||
"NoPerspective", // 13,
|
||||
"Flat", // 14,
|
||||
"Patch", // 15,
|
||||
"Centroid", // 16,
|
||||
"Sample", // 17,
|
||||
"Invariant", // 18,
|
||||
"Restrict", // 19,
|
||||
"Aliased", // 20,
|
||||
"Volatile", // 21,
|
||||
"Constant", // 22,
|
||||
"Coherent", // 23,
|
||||
"NonWritable", // 24,
|
||||
"NonReadable", // 25,
|
||||
"Uniform", // 26,
|
||||
nullptr, // 27
|
||||
"SaturatedConversion", // 28,
|
||||
"Stream", // 29,
|
||||
"Location", // 30,
|
||||
"Component", // 31,
|
||||
"Index", // 32,
|
||||
"Binding", // 33,
|
||||
"DescriptorSet", // 34,
|
||||
"Offset", // 35,
|
||||
"XfbBuffer", // 36,
|
||||
"XfbStride", // 37,
|
||||
"FuncParamAttr", // 38,
|
||||
"FPRoundingMode", // 39,
|
||||
"FPFastMathMode", // 40,
|
||||
"LinkageAttributes", // 41,
|
||||
"NoContraction", // 42,
|
||||
"InputAttachmentIndex", // 43,
|
||||
"Alignment", // 44,
|
||||
};
|
||||
|
||||
static const OpInfo opInfo[] = {
|
||||
{"Nop"}, // 0,
|
||||
{"Undef"}, // 1,
|
||||
{"SourceContinued"}, // 2,
|
||||
{"Source"}, // 3,
|
||||
{"SourceExtension"}, // 4,
|
||||
{"Name"}, // 5,
|
||||
{"MemberName"}, // 6,
|
||||
{"String"}, // 7,
|
||||
{"Line"}, // 8,
|
||||
{nullptr}, // 9
|
||||
{"Extension"}, // 10,
|
||||
{"ExtInstImport"}, // 11,
|
||||
{"ExtInst"}, // 12,
|
||||
{nullptr}, // 13
|
||||
{"MemoryModel"}, // 14,
|
||||
{"EntryPoint"}, // 15,
|
||||
{"ExecutionMode"}, // 16,
|
||||
{"Capability"}, // 17,
|
||||
{nullptr}, // 18
|
||||
{"TypeVoid"}, // 19,
|
||||
{"TypeBool"}, // 20,
|
||||
{"TypeInt"}, // 21,
|
||||
{"TypeFloat"}, // 22,
|
||||
{"TypeVector"}, // 23,
|
||||
{"TypeMatrix"}, // 24,
|
||||
{"TypeImage"}, // 25,
|
||||
{"TypeSampler"}, // 26,
|
||||
{"TypeSampledImage"}, // 27,
|
||||
{"TypeArray"}, // 28,
|
||||
{"TypeRuntimeArray"}, // 29,
|
||||
{"TypeStruct"}, // 30,
|
||||
{"TypeOpaque"}, // 31,
|
||||
{"TypePointer"}, // 32,
|
||||
{"TypeFunction"}, // 33,
|
||||
{"TypeEvent"}, // 34,
|
||||
{"TypeDeviceEvent"}, // 35,
|
||||
{"TypeReserveId"}, // 36,
|
||||
{"TypeQueue"}, // 37,
|
||||
{"TypePipe"}, // 38,
|
||||
{"TypeForwardPointer"}, // 39,
|
||||
{nullptr}, // 40
|
||||
{"ConstantTrue"}, // 41,
|
||||
{"ConstantFalse"}, // 42,
|
||||
{"Constant"}, // 43,
|
||||
{"ConstantComposite"}, // 44,
|
||||
{"ConstantSampler"}, // 45,
|
||||
{"ConstantNull"}, // 46,
|
||||
{nullptr}, // 47
|
||||
{"SpecConstantTrue"}, // 48,
|
||||
{"SpecConstantFalse"}, // 49,
|
||||
{"SpecConstant"}, // 50,
|
||||
{"SpecConstantComposite"}, // 51,
|
||||
{"SpecConstantOp"}, // 52,
|
||||
{nullptr}, // 53
|
||||
{"Function"}, // 54,
|
||||
{"FunctionParameter"}, // 55,
|
||||
{"FunctionEnd"}, // 56,
|
||||
{"FunctionCall"}, // 57,
|
||||
{nullptr}, // 58
|
||||
{"Variable"}, // 59,
|
||||
{"ImageTexelPointer"}, // 60,
|
||||
{"Load"}, // 61,
|
||||
{"Store"}, // 62,
|
||||
{"CopyMemory"}, // 63,
|
||||
{"CopyMemorySized"}, // 64,
|
||||
{"AccessChain"}, // 65,
|
||||
{"InBoundsAccessChain"}, // 66,
|
||||
{"PtrAccessChain"}, // 67,
|
||||
{"ArrayLength"}, // 68,
|
||||
{"GenericPtrMemSemantics"}, // 69,
|
||||
{"InBoundsPtrAccessChain"}, // 70,
|
||||
{"Decorate"}, // 71,
|
||||
{"MemberDecorate"}, // 72,
|
||||
{"DecorationGroup"}, // 73,
|
||||
{"GroupDecorate"}, // 74,
|
||||
{"GroupMemberDecorate"}, // 75,
|
||||
{nullptr}, // 76
|
||||
{"VectorExtractDynamic"}, // 77,
|
||||
{"VectorInsertDynamic"}, // 78,
|
||||
{"VectorShuffle"}, // 79,
|
||||
{"CompositeConstruct"}, // 80,
|
||||
{"CompositeExtract"}, // 81,
|
||||
{"CompositeInsert"}, // 82,
|
||||
{"CopyObject"}, // 83,
|
||||
{"Transpose"}, // 84,
|
||||
{nullptr}, // 85
|
||||
{"SampledImage"}, // 86,
|
||||
{"ImageSampleImplicitLod"}, // 87,
|
||||
{"ImageSampleExplicitLod"}, // 88,
|
||||
{"ImageSampleDrefImplicitLod"}, // 89,
|
||||
{"ImageSampleDrefExplicitLod"}, // 90,
|
||||
{"ImageSampleProjImplicitLod"}, // 91,
|
||||
{"ImageSampleProjExplicitLod"}, // 92,
|
||||
{"ImageSampleProjDrefImplicitLod"}, // 93,
|
||||
{"ImageSampleProjDrefExplicitLod"}, // 94,
|
||||
{"ImageFetch"}, // 95,
|
||||
{"ImageGather"}, // 96,
|
||||
{"ImageDrefGather"}, // 97,
|
||||
{"ImageRead"}, // 98,
|
||||
{"ImageWrite"}, // 99,
|
||||
{"Image"}, // 100,
|
||||
{"ImageQueryFormat"}, // 101,
|
||||
{"ImageQueryOrder"}, // 102,
|
||||
{"ImageQuerySizeLod"}, // 103,
|
||||
{"ImageQuerySize"}, // 104,
|
||||
{"ImageQueryLod"}, // 105,
|
||||
{"ImageQueryLevels"}, // 106,
|
||||
{"ImageQuerySamples"}, // 107,
|
||||
{nullptr}, // 108
|
||||
{"ConvertFToU"}, // 109,
|
||||
{"ConvertFToS"}, // 110,
|
||||
{"ConvertSToF"}, // 111,
|
||||
{"ConvertUToF"}, // 112,
|
||||
{"UConvert"}, // 113,
|
||||
{"SConvert"}, // 114,
|
||||
{"FConvert"}, // 115,
|
||||
{"QuantizeToF16"}, // 116,
|
||||
{"ConvertPtrToU"}, // 117,
|
||||
{"SatConvertSToU"}, // 118,
|
||||
{"SatConvertUToS"}, // 119,
|
||||
{"ConvertUToPtr"}, // 120,
|
||||
{"PtrCastToGeneric"}, // 121,
|
||||
{"GenericCastToPtr"}, // 122,
|
||||
{"GenericCastToPtrExplicit"}, // 123,
|
||||
{"Bitcast"}, // 124,
|
||||
{nullptr}, // 125
|
||||
{"SNegate"}, // 126,
|
||||
{"FNegate"}, // 127,
|
||||
{"IAdd"}, // 128,
|
||||
{"FAdd", "+"}, // 129,
|
||||
{"ISub"}, // 130,
|
||||
{"FSub", "-"}, // 131,
|
||||
{"IMul"}, // 132,
|
||||
{"FMul", "*"}, // 133,
|
||||
{"UDiv"}, // 134,
|
||||
{"SDiv"}, // 135,
|
||||
{"FDiv", "/"}, // 136,
|
||||
{"UMod"}, // 137,
|
||||
{"SRem"}, // 138,
|
||||
{"SMod"}, // 139,
|
||||
{"FRem"}, // 140,
|
||||
{"FMod", "%"}, // 141,
|
||||
{"VectorTimesScalar"}, // 142,
|
||||
{"MatrixTimesScalar"}, // 143,
|
||||
{"VectorTimesMatrix"}, // 144,
|
||||
{"MatrixTimesVector"}, // 145,
|
||||
{"MatrixTimesMatrix"}, // 146,
|
||||
{"OuterProduct"}, // 147,
|
||||
{"Dot", " dot "}, // 148,
|
||||
{"IAddCarry"}, // 149,
|
||||
{"ISubBorrow"}, // 150,
|
||||
{"UMulExtended"}, // 151,
|
||||
{"SMulExtended"}, // 152,
|
||||
{nullptr}, // 153
|
||||
{"Any"}, // 154,
|
||||
{"All"}, // 155,
|
||||
{"IsNan"}, // 156,
|
||||
{"IsInf"}, // 157,
|
||||
{"IsFinite"}, // 158,
|
||||
{"IsNormal"}, // 159,
|
||||
{"SignBitSet"}, // 160,
|
||||
{"LessOrGreater"}, // 161,
|
||||
{"Ordered"}, // 162,
|
||||
{"Unordered"}, // 163,
|
||||
{"LogicalEqual"}, // 164,
|
||||
{"LogicalNotEqual"}, // 165,
|
||||
{"LogicalOr"}, // 166,
|
||||
{"LogicalAnd"}, // 167,
|
||||
{"LogicalNot"}, // 168,
|
||||
{"Select"}, // 169,
|
||||
{"IEqual"}, // 170,
|
||||
{"INotEqual"}, // 171,
|
||||
{"UGreaterThan"}, // 172,
|
||||
{"SGreaterThan"}, // 173,
|
||||
{"UGreaterThanEqual"}, // 174,
|
||||
{"SGreaterThanEqual"}, // 175,
|
||||
{"ULessThan"}, // 176,
|
||||
{"SLessThan"}, // 177,
|
||||
{"ULessThanEqual"}, // 178,
|
||||
{"SLessThanEqual"}, // 179,
|
||||
{"FOrdEqual", "=="}, // 180,
|
||||
{"FUnordEqual", "=="}, // 181,
|
||||
{"FOrdNotEqual", "!="}, // 182,
|
||||
{"FUnordNotEqual", "!="}, // 183,
|
||||
{"FOrdLessThan"}, // 184,
|
||||
{"FUnordLessThan"}, // 185,
|
||||
{"FOrdGreaterThan"}, // 186,
|
||||
{"FUnordGreaterThan"}, // 187,
|
||||
{"FOrdLessThanEqual"}, // 188,
|
||||
{"FUnordLessThanEqual"}, // 189,
|
||||
{"FOrdGreaterThanEqual"}, // 190,
|
||||
{"FUnordGreaterThanEqual"}, // 191,
|
||||
{ nullptr }, // 192
|
||||
{ nullptr }, // 193
|
||||
{"ShiftRightLogical"}, // 194,
|
||||
{"ShiftRightArithmetic"}, // 195,
|
||||
{"ShiftLeftLogical"}, // 196,
|
||||
{"BitwiseOr", "|"}, // 197,
|
||||
{"BitwiseXor", "^"}, // 198,
|
||||
{"BitwiseAnd", "&"}, // 199,
|
||||
{"Not", "~"}, // 200,
|
||||
{"BitFieldInsert"}, // 201,
|
||||
{"BitFieldSExtract"}, // 202,
|
||||
{"BitFieldUExtract"}, // 203,
|
||||
{"BitReverse"}, // 204,
|
||||
{"BitCount"}, // 205,
|
||||
{nullptr},
|
||||
{"DPdx"}, // 207,
|
||||
{"DPdy"}, // 208,
|
||||
{"Fwidth"}, // 209,
|
||||
{"DPdxFine"}, // 210,
|
||||
{"DPdyFine"}, // 211,
|
||||
{"FwidthFine"}, // 212,
|
||||
{"DPdxCoarse"}, // 213,
|
||||
{"DPdyCoarse"}, // 214,
|
||||
{"FwidthCoarse"}, // 215,
|
||||
{nullptr}, // 216
|
||||
{nullptr}, // 217
|
||||
{"EmitVertex"}, // 218,
|
||||
{"EndPrimitive"}, // 219,
|
||||
{"EmitStreamVertex"}, // 220,
|
||||
{"EndStreamPrimitive"}, // 221,
|
||||
{nullptr}, // 222
|
||||
{nullptr}, // 223
|
||||
{"ControlBarrier"}, // 224,
|
||||
{"MemoryBarrier"}, // 225,
|
||||
{nullptr}, // 226
|
||||
{"AtomicLoad"}, // 227,
|
||||
{"AtomicStore"}, // 228,
|
||||
{"AtomicExchange"}, // 229,
|
||||
{"AtomicCompareExchange"}, // 230,
|
||||
{"AtomicCompareExchangeWeak"}, // 231,
|
||||
{"AtomicIIncrement"}, // 232,
|
||||
{"AtomicIDecrement"}, // 233,
|
||||
{"AtomicIAdd"}, // 234,
|
||||
{"AtomicISub"}, // 235,
|
||||
{"AtomicSMin"}, // 236,
|
||||
{"AtomicUMin"}, // 237,
|
||||
{"AtomicSMax"}, // 238,
|
||||
{"AtomicUMax"}, // 239,
|
||||
{"AtomicAnd"}, // 240,
|
||||
{"AtomicOr"}, // 241,
|
||||
{"AtomicXor"}, // 242,
|
||||
{ nullptr }, // 243,
|
||||
{ nullptr }, // 244,
|
||||
{"Phi"}, // 245,
|
||||
{"LoopMerge"}, // 246,
|
||||
{"SelectionMerge"}, // 247,
|
||||
{"Label"}, // 248,
|
||||
{"Branch"}, // 249,
|
||||
{"BranchConditional"}, // 250,
|
||||
{"Switch"}, // 251,
|
||||
{"Kill"}, // 252,
|
||||
{"Return"}, // 253,
|
||||
{"ReturnValue"}, // 254,
|
||||
{"Unreachable"}, // 255,
|
||||
{"LifetimeStart"}, // 256,
|
||||
{"LifetimeStop"}, // 257,
|
||||
{ nullptr },
|
||||
{"GroupAsyncCopy"}, // 259,
|
||||
{"GroupWaitEvents"}, // 260,
|
||||
{"GroupAll"}, // 261,
|
||||
{"GroupAny"}, // 262,
|
||||
{"GroupBroadcast"}, // 263,
|
||||
{"GroupIAdd"}, // 264,
|
||||
{"GroupFAdd"}, // 265,
|
||||
{"GroupFMin"}, // 266,
|
||||
{"GroupUMin"}, // 267,
|
||||
{"GroupSMin"}, // 268,
|
||||
{"GroupFMax"}, // 269,
|
||||
{"GroupUMax"}, // 270,
|
||||
{"GroupSMax"}, // 271,
|
||||
{nullptr}, // 272
|
||||
{nullptr}, // 273
|
||||
{"ReadPipe"}, // 274,
|
||||
{"WritePipe"}, // 275,
|
||||
{"ReservedReadPipe"}, // 276,
|
||||
{"ReservedWritePipe"}, // 277,
|
||||
{"ReserveReadPipePackets"}, // 278,
|
||||
{"ReserveWritePipePackets"}, // 279,
|
||||
{"CommitReadPipe"}, // 280,
|
||||
{"CommitWritePipe"}, // 281,
|
||||
{"IsValidReserveId"}, // 282,
|
||||
{"GetNumPipePackets"}, // 283,
|
||||
{"GetMaxPipePackets"}, // 284,
|
||||
{"GroupReserveReadPipePackets"}, // 285,
|
||||
{"GroupReserveWritePipePackets"}, // 286,
|
||||
{"GroupCommitReadPipe"}, // 287,
|
||||
{"GroupCommitWritePipe"}, // 288,
|
||||
{ nullptr }, // 289
|
||||
{ nullptr }, // 290
|
||||
{"EnqueueMarker"}, // 291,
|
||||
{"EnqueueKernel"}, // 292,
|
||||
{"GetKernelNDrangeSubGroupCount"}, // 293,
|
||||
{"GetKernelNDrangeMaxSubGroupSize"}, // 294,
|
||||
{"GetKernelWorkGroupSize"}, // 295,
|
||||
{"GetKernelPreferredWorkGroupSizeMultiple"}, // 296,
|
||||
{"RetainEvent"}, // 297,
|
||||
{"ReleaseEvent"}, // 298,
|
||||
{"CreateUserEvent"}, // 299,
|
||||
{"IsValidEvent"}, // 300,
|
||||
{"SetUserEventStatus"}, // 301,
|
||||
{"CaptureEventProfilingInfo"}, // 302,
|
||||
{"GetDefaultQueue"}, // 303,
|
||||
{"BuildNDRange"}, // 304,
|
||||
{"ImageSparseSampleImplicitLod"}, // 305,
|
||||
{"ImageSparseSampleExplicitLod"}, // 306,
|
||||
{"ImageSparseSampleDrefImplicitLod"}, // 307,
|
||||
{"ImageSparseSampleDrefExplicitLod"}, // 308,
|
||||
{"ImageSparseSampleProjImplicitLod"}, // 309,
|
||||
{"ImageSparseSampleProjExplicitLod"}, // 310,
|
||||
{"ImageSparseSampleProjDrefImplicitLod"}, // 311,
|
||||
{"ImageSparseSampleProjDrefExplicitLod"}, // 312,
|
||||
{"ImageSparseFetch"}, // 313,
|
||||
{"ImageSparseGather"}, // 314,
|
||||
{"ImageSparseDrefGather"}, // 315,
|
||||
{"ImageSparseTexelsResident"}, // 316,
|
||||
{"NoLine"}, // 317,
|
||||
{"AtomicFlagTestAndSet"}, // 318,
|
||||
{"AtomicFlagClear"}, // 319,
|
||||
};
|
||||
|
||||
static std::string ReadSpirvString(const std::vector<uint32_t> &spirv, int offset, int *outOffset = nullptr) {
|
||||
bool done = false;
|
||||
std::string temp;
|
||||
while (!done) {
|
||||
uint32_t data = spirv[offset++];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char c = (char)(data & 0xff);
|
||||
if (!c) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
temp.push_back(data);
|
||||
data >>= 8;
|
||||
}
|
||||
if (offset == (int)spirv.size())
|
||||
break;
|
||||
}
|
||||
if (outOffset)
|
||||
*outOffset = offset;
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool DisassembleSPIRV(std::vector<uint32_t> spirv, std::string *output) {
|
||||
if (spirv.size() < 10) {
|
||||
*output = "Too small";
|
||||
return false;
|
||||
}
|
||||
uint32_t magic = spirv[0];
|
||||
uint32_t version = spirv[1];
|
||||
uint32_t generator = spirv[2];
|
||||
|
||||
int bound = (int)spirv[3]; // Max ID used in file.
|
||||
// spirv[4] is reserved for schema.
|
||||
std::vector<SpirvID> ids;
|
||||
ids.resize(bound);
|
||||
for (int i = 0; i < bound; i++) {
|
||||
ids[i].name = StringFromFormat("%%%d", i);
|
||||
}
|
||||
|
||||
if (magic != 0x07230203) {
|
||||
*output = "Not SPIRV";
|
||||
return false;
|
||||
}
|
||||
|
||||
int indent = 0;
|
||||
|
||||
char *buffer = new char[1024 * 1024];
|
||||
char *p = buffer;
|
||||
|
||||
WRITE(p, "// ======= SPIR-V version %08x =======\n// Max ID: %d\n", version, bound); // GLSL ES
|
||||
|
||||
int i = 5;
|
||||
while (i < (int)spirv.size()) {
|
||||
uint32_t d = spirv[i];
|
||||
int wordCount = d >> 16;
|
||||
int opcode = d & 0xFFFF;
|
||||
// Force to a valid index in the array.
|
||||
const OpInfo &op = opInfo[opcode >= (int)ARRAY_SIZE(opInfo) ? 0 : opcode];
|
||||
int target = (i < (int)spirv.size() - 1) ? spirv[(i + 1)] : 0; // Not always, but used often enough that we get it here.
|
||||
int source, source2, resType;
|
||||
std::string name;
|
||||
switch (opcode) {
|
||||
case spv::OpTypeVoid:
|
||||
case spv::OpTypeBool:
|
||||
case spv::OpTypeInt:
|
||||
case spv::OpTypeFloat:
|
||||
case spv::OpTypeMatrix:
|
||||
case spv::OpTypeImage:
|
||||
case spv::OpTypeSampler:
|
||||
case spv::OpTypeSampledImage:
|
||||
case spv::OpTypeRuntimeArray:
|
||||
case spv::OpTypeOpaque:
|
||||
case spv::OpTypePointer:
|
||||
case spv::OpTypeFunction:
|
||||
case spv::OpTypeEvent:
|
||||
case spv::OpTypeDeviceEvent:
|
||||
case spv::OpTypeReserveId:
|
||||
case spv::OpTypeQueue:
|
||||
case spv::OpTypePipe:
|
||||
case spv::OpTypeForwardPointer:
|
||||
ids[target].name = op.name + 4; // Remove "Type"
|
||||
ids[target].opcode = opcode;
|
||||
break;
|
||||
case spv::OpTypeVector:
|
||||
source = spirv[i + 2];
|
||||
source2 = spirv[i + 3];
|
||||
ids[target].name = ids[source].name + StringFromFormat("%d", source2);
|
||||
break;
|
||||
case spv::OpTypeArray:
|
||||
source = spirv[i + 2];
|
||||
source2 = spirv[i + 3];
|
||||
ids[target].name = ids[source].name + "[" + ids[source2].name + "]";
|
||||
break;
|
||||
case spv::OpTypeStruct:
|
||||
{
|
||||
ids[target].name = "struct" + ids[target].name;
|
||||
WRITE(p, "struct {\n");
|
||||
if (wordCount == 3) {
|
||||
source = spirv[i + 2];
|
||||
WRITE(p, " %s\n", ids[source].name.c_str());
|
||||
} else {
|
||||
int numMembers = (wordCount - 2) / 2;
|
||||
for (int m = 0; m < numMembers; m++) {
|
||||
int id = spirv[i + 2 + m];
|
||||
int type = spirv[i + 2 + m + numMembers];
|
||||
WRITE(p, " %s %s;\n", ids[type].name.c_str(), ids[id].name.c_str());
|
||||
}
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
}
|
||||
break;
|
||||
case spv::OpVariable:
|
||||
resType = spirv[i + 1];
|
||||
target = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
source2 = spirv[i + 4];
|
||||
ids[target].name = storageClassNames[source];
|
||||
break;
|
||||
case spv::OpDecorate:
|
||||
source = spirv[i + 2];
|
||||
ids[target].name += std::string("[") + decorationNames[source] + "]";
|
||||
break;
|
||||
case spv::OpName:
|
||||
ids[target].name = ReadSpirvString(spirv, i + 2);
|
||||
// WRITE(p, "Name %d: '%s'\n", target, ids[target].name.c_str());
|
||||
break;
|
||||
case spv::OpMemberName:
|
||||
break;
|
||||
case spv::OpStore:
|
||||
source = spirv[i + 2];
|
||||
WRITE(p, "Store(%s, %s)\n", ids[target].name.c_str(), ids[source].name.c_str());
|
||||
break;
|
||||
case spv::OpLoad:
|
||||
resType = spirv[i + 1];
|
||||
target = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
WRITE(p, "%s (%s) := Load(%s)\n", ids[target].name.c_str(), ids[resType].name.c_str(), ids[source].name.c_str());
|
||||
break;
|
||||
case spv::OpFAdd:
|
||||
case spv::OpFMul:
|
||||
case spv::OpFDiv:
|
||||
case spv::OpFSub:
|
||||
resType = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
source2 = spirv[i + 4];
|
||||
WRITE(p, "%s (%s) := %s %s %s\n", ids[target].name.c_str(), ids[resType].name.c_str(), ids[source].name.c_str(), op.extra, ids[source2].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpCapability:
|
||||
case spv::OpMemoryModel:
|
||||
case spv::OpExtInstImport:
|
||||
case spv::OpExecutionMode:
|
||||
case spv::OpGroupAsyncCopy:
|
||||
case spv::OpSource:
|
||||
case spv::OpExtension:
|
||||
// hide these for now
|
||||
break;
|
||||
|
||||
case spv::OpEntryPoint:
|
||||
source = spirv[i + 1];
|
||||
source2 = spirv[i + 2];
|
||||
name = ReadSpirvString(spirv, i + 3);
|
||||
WRITE(p, "EntryPoint %s: '%s' %s : %s\n", executionModelNames[target], ids[source].name.c_str(), ids[source2].name.c_str(), name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpFunction:
|
||||
resType = spirv[i + 1];
|
||||
target = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
ids[target].name = ids[resType].name + "()";
|
||||
WRITE(p, "Function %s {\n", ids[target].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpLabel:
|
||||
WRITE(p, "label %s:\n", ids[target].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpReturnValue:
|
||||
WRITE(p, "return %s\n", ids[target].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpReturn:
|
||||
WRITE(p, "return\n");
|
||||
break;
|
||||
|
||||
case spv::OpFunctionEnd:
|
||||
WRITE(p, "}\n");
|
||||
break;
|
||||
|
||||
case spv::OpSourceExtension:
|
||||
break;
|
||||
|
||||
default:
|
||||
WRITE(p, "%s (%d data words)\n", op.name, wordCount - 1);
|
||||
break;
|
||||
}
|
||||
i += wordCount;
|
||||
}
|
||||
|
||||
*output = buffer;
|
||||
delete[] buffer;
|
||||
return true;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Mostly just a toy to understand SPIR-V better. Not an accurate SPIR-V disassembler,
|
||||
// and the result will not reassemble.
|
||||
|
||||
bool DisassembleSPIRV(std::vector<uint32_t> spirv, std::string *output);
|
||||
+193
-94
@@ -60,7 +60,7 @@ static const char *validationLayers[] = {
|
||||
std::string VulkanVendorString(uint32_t vendorId) {
|
||||
switch (vendorId) {
|
||||
case VULKAN_VENDOR_INTEL: return "Intel";
|
||||
case VULKAN_VENDOR_NVIDIA: return "nVidia";
|
||||
case VULKAN_VENDOR_NVIDIA: return "NVIDIA";
|
||||
case VULKAN_VENDOR_AMD: return "AMD";
|
||||
case VULKAN_VENDOR_ARM: return "ARM";
|
||||
case VULKAN_VENDOR_QUALCOMM: return "Qualcomm";
|
||||
@@ -77,6 +77,8 @@ const char *PresentModeString(VkPresentModeKHR presentMode) {
|
||||
case VK_PRESENT_MODE_MAILBOX_KHR: return "MAILBOX";
|
||||
case VK_PRESENT_MODE_FIFO_KHR: return "FIFO";
|
||||
case VK_PRESENT_MODE_FIFO_RELAXED_KHR: return "FIFO_RELAXED";
|
||||
case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: return "SHARED_DEMAND_REFRESH_KHR";
|
||||
case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: return "SHARED_CONTINUOUS_REFRESH_KHR";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
@@ -120,9 +122,6 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
//#if defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
// instance_extensions_enabled_.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
||||
//#endif
|
||||
//#if defined(VK_USE_PLATFORM_MIR_KHR)
|
||||
// instance_extensions_enabled_.push_back(VK_KHR_MIR_SURFACE_EXTENSION_NAME);
|
||||
//#endif
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
if (IsInstanceExtensionAvailable(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) {
|
||||
instance_extensions_enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
@@ -131,18 +130,32 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
#endif
|
||||
|
||||
if (flags_ & VULKAN_FLAG_VALIDATE) {
|
||||
if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
|
||||
if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
|
||||
// Enable the validation layers
|
||||
for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) {
|
||||
instance_layer_names_.push_back(validationLayers[i]);
|
||||
device_layer_names_.push_back(validationLayers[i]);
|
||||
}
|
||||
instance_extensions_enabled_.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
extensionsLookup_.EXT_debug_utils = true;
|
||||
} else if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) {
|
||||
instance_layer_names_.push_back(validationLayers[i]);
|
||||
device_layer_names_.push_back(validationLayers[i]);
|
||||
}
|
||||
instance_extensions_enabled_.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
||||
extensionsLookup_.EXT_debug_report = true;
|
||||
} else {
|
||||
ELOG("Validation layer extension not available - not enabling Vulkan validation.");
|
||||
flags_ &= ~VULKAN_FLAG_VALIDATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsInstanceExtensionAvailable(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
|
||||
instance_extensions_enabled_.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||
extensionsLookup_.KHR_get_physical_device_properties2 = true;
|
||||
}
|
||||
|
||||
// Validate that all the instance extensions we ask for are actually available.
|
||||
for (auto ext : instance_extensions_enabled_) {
|
||||
if (!IsInstanceExtensionAvailable(ext))
|
||||
@@ -190,7 +203,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
return res;
|
||||
}
|
||||
|
||||
VulkanLoadInstanceFunctions(instance_);
|
||||
VulkanLoadInstanceFunctions(instance_, extensionsLookup_);
|
||||
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
|
||||
WLOG("CheckLayers for instance failed");
|
||||
// init_error_ = "Failed to validate instance layers";
|
||||
@@ -222,8 +235,25 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < gpu_count; i++) {
|
||||
vkGetPhysicalDeviceProperties(physical_devices_[i], &physicalDeviceProperties_[i]);
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2) {
|
||||
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};
|
||||
props2.pNext = &pushProps;
|
||||
pushProps.pNext = &extHostMemProps;
|
||||
vkGetPhysicalDeviceProperties2KHR(physical_devices_[i], &props2);
|
||||
// Don't want bad pointers sitting around.
|
||||
props2.pNext = nullptr;
|
||||
pushProps.pNext = nullptr;
|
||||
physicalDeviceProperties_[i].properties = props2.properties;
|
||||
physicalDeviceProperties_[i].pushDescriptorProperties = pushProps;
|
||||
physicalDeviceProperties_[i].externalMemoryHostProperties = extHostMemProps;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < gpu_count; i++) {
|
||||
vkGetPhysicalDeviceProperties(physical_devices_[i], &physicalDeviceProperties_[i].properties);
|
||||
}
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
@@ -423,7 +453,7 @@ bool VulkanContext::CheckLayers(const std::vector<LayerProperties> &layer_props,
|
||||
|
||||
int VulkanContext::GetPhysicalDeviceByName(std::string name) {
|
||||
for (size_t i = 0; i < physical_devices_.size(); i++) {
|
||||
if (physicalDeviceProperties_[i].deviceName == name)
|
||||
if (physicalDeviceProperties_[i].properties.deviceName == name)
|
||||
return (int)i;
|
||||
}
|
||||
return -1;
|
||||
@@ -505,41 +535,56 @@ void VulkanContext::ChooseDevice(int physical_device) {
|
||||
ELOG("Could not find a usable depth stencil format.");
|
||||
}
|
||||
|
||||
// This is as good a place as any to do this
|
||||
// This is as good a place as any to do this.
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties);
|
||||
ILOG("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;
|
||||
ILOG(" %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
|
||||
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_);
|
||||
memset(&featuresEnabled_, 0, sizeof(featuresEnabled_));
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2) {
|
||||
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
|
||||
vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2);
|
||||
deviceFeatures_.available = features2.features;
|
||||
} else {
|
||||
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available);
|
||||
}
|
||||
|
||||
deviceFeatures_.enabled = {};
|
||||
|
||||
// Enable a few safe ones if they are available.
|
||||
if (featuresAvailable_.dualSrcBlend && physicalDeviceProperties_[physical_device_].vendorID != VULKAN_VENDOR_QUALCOMM) {
|
||||
featuresEnabled_.dualSrcBlend = true;
|
||||
if (deviceFeatures_.available.dualSrcBlend) {
|
||||
deviceFeatures_.enabled.dualSrcBlend = true;
|
||||
}
|
||||
if (featuresAvailable_.largePoints) {
|
||||
featuresEnabled_.largePoints = true;
|
||||
if (deviceFeatures_.available.largePoints) {
|
||||
deviceFeatures_.enabled.largePoints = true;
|
||||
}
|
||||
if (featuresAvailable_.wideLines) {
|
||||
featuresEnabled_.wideLines = true;
|
||||
if (deviceFeatures_.available.wideLines) {
|
||||
deviceFeatures_.enabled.wideLines = true;
|
||||
}
|
||||
if (featuresAvailable_.geometryShader) {
|
||||
featuresEnabled_.geometryShader = true;
|
||||
if (deviceFeatures_.available.logicOp) {
|
||||
deviceFeatures_.enabled.logicOp = true;
|
||||
}
|
||||
if (featuresAvailable_.logicOp) {
|
||||
featuresEnabled_.logicOp = true;
|
||||
if (deviceFeatures_.available.depthClamp) {
|
||||
deviceFeatures_.enabled.depthClamp = true;
|
||||
}
|
||||
if (featuresAvailable_.depthClamp) {
|
||||
featuresEnabled_.depthClamp = true;
|
||||
if (deviceFeatures_.available.depthBounds) {
|
||||
deviceFeatures_.enabled.depthBounds = true;
|
||||
}
|
||||
if (featuresAvailable_.depthBounds) {
|
||||
featuresEnabled_.depthBounds = true;
|
||||
}
|
||||
if (featuresAvailable_.samplerAnisotropy) {
|
||||
featuresEnabled_.samplerAnisotropy = true;
|
||||
if (deviceFeatures_.available.samplerAnisotropy) {
|
||||
deviceFeatures_.enabled.samplerAnisotropy = true;
|
||||
}
|
||||
// For easy wireframe mode, someday.
|
||||
if (featuresEnabled_.fillModeNonSolid) {
|
||||
featuresEnabled_.fillModeNonSolid = true;
|
||||
if (deviceFeatures_.available.fillModeNonSolid) {
|
||||
deviceFeatures_.enabled.fillModeNonSolid = true;
|
||||
}
|
||||
|
||||
GetDeviceLayerExtensionList(nullptr, device_extension_properties_);
|
||||
@@ -563,8 +608,8 @@ VkResult VulkanContext::CreateDevice() {
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
VkDeviceQueueCreateInfo queue_info{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
|
||||
float queue_priorities[1] = { 1.0f };
|
||||
VkDeviceQueueCreateInfo queue_info{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
|
||||
float queue_priorities[1] = {1.0f};
|
||||
queue_info.queueCount = 1;
|
||||
queue_info.pQueuePriorities = queue_priorities;
|
||||
bool found = false;
|
||||
@@ -577,7 +622,25 @@ VkResult VulkanContext::CreateDevice() {
|
||||
}
|
||||
assert(found);
|
||||
|
||||
deviceExtensionsLookup_.DEDICATED_ALLOCATION = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||
extensionsLookup_.KHR_maintenance1 = EnableDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
|
||||
extensionsLookup_.KHR_maintenance2 = EnableDeviceExtension(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
|
||||
extensionsLookup_.KHR_maintenance3 = EnableDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
extensionsLookup_.KHR_multiview = EnableDeviceExtension(VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||
|
||||
if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) {
|
||||
extensionsLookup_.KHR_get_memory_requirements2 = true;
|
||||
extensionsLookup_.KHR_dedicated_allocation = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||
}
|
||||
if (EnableDeviceExtension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) {
|
||||
if (EnableDeviceExtension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME)) {
|
||||
extensionsLookup_.EXT_external_memory_host = EnableDeviceExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
if (EnableDeviceExtension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
|
||||
extensionsLookup_.KHR_create_renderpass2 = true;
|
||||
extensionsLookup_.KHR_depth_stencil_resolve = EnableDeviceExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
|
||||
}
|
||||
extensionsLookup_.EXT_shader_stencil_export = EnableDeviceExtension(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
|
||||
|
||||
VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
|
||||
device_info.queueCreateInfoCount = 1;
|
||||
@@ -586,13 +649,14 @@ VkResult VulkanContext::CreateDevice() {
|
||||
device_info.ppEnabledLayerNames = device_info.enabledLayerCount ? device_layer_names_.data() : nullptr;
|
||||
device_info.enabledExtensionCount = (uint32_t)device_extensions_enabled_.size();
|
||||
device_info.ppEnabledExtensionNames = device_info.enabledExtensionCount ? device_extensions_enabled_.data() : nullptr;
|
||||
device_info.pEnabledFeatures = &featuresEnabled_;
|
||||
device_info.pEnabledFeatures = &deviceFeatures_.enabled;
|
||||
|
||||
VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_);
|
||||
if (res != VK_SUCCESS) {
|
||||
init_error_ = "Unable to create Vulkan device";
|
||||
ELOG("Unable to create Vulkan device");
|
||||
} else {
|
||||
VulkanLoadDeviceFunctions(device_);
|
||||
VulkanLoadDeviceFunctions(device_, extensionsLookup_);
|
||||
}
|
||||
ILOG("Device created.\n");
|
||||
VulkanSetAvailable(true);
|
||||
@@ -608,13 +672,11 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun
|
||||
}
|
||||
ILOG("Registering debug report callback");
|
||||
|
||||
VkDebugReportCallbackCreateInfoEXT cb = {};
|
||||
cb.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
||||
cb.pNext = nullptr;
|
||||
VkDebugReportCallbackCreateInfoEXT cb{VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT};
|
||||
cb.flags = bits;
|
||||
cb.pfnCallback = dbgFunc;
|
||||
cb.pUserData = userdata;
|
||||
VkResult res = dyn_vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback);
|
||||
VkResult res = vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback);
|
||||
switch (res) {
|
||||
case VK_SUCCESS:
|
||||
msg_callbacks.push_back(msg_callback);
|
||||
@@ -628,49 +690,66 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun
|
||||
}
|
||||
|
||||
void VulkanContext::DestroyDebugMsgCallback() {
|
||||
if (!extensionsLookup_.EXT_debug_report)
|
||||
return;
|
||||
while (msg_callbacks.size() > 0) {
|
||||
dyn_vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr);
|
||||
vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr);
|
||||
msg_callbacks.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2, int width, int height) {
|
||||
VkResult VulkanContext::InitDebugUtilsCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback, int bits, void *userdata) {
|
||||
VkDebugUtilsMessengerCreateInfoEXT callback1{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};
|
||||
callback1.messageSeverity = bits;
|
||||
callback1.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
callback1.pfnUserCallback = callback;
|
||||
callback1.pUserData = userdata;
|
||||
VkDebugUtilsMessengerEXT messenger;
|
||||
VkResult res = vkCreateDebugUtilsMessengerEXT(instance_, &callback1, nullptr, &messenger);
|
||||
if (res != VK_SUCCESS) {
|
||||
ELOG("Failed to register debug callback with vkCreateDebugUtilsMessengerEXT");
|
||||
// Do error handling for VK_ERROR_OUT_OF_MEMORY
|
||||
} else {
|
||||
ILOG("Debug callback registered with vkCreateDebugUtilsMessengerEXT.");
|
||||
utils_callbacks.push_back(messenger);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void VulkanContext::DestroyDebugUtilsCallback() {
|
||||
if (!extensionsLookup_.EXT_debug_utils)
|
||||
return;
|
||||
while (utils_callbacks.size() > 0) {
|
||||
vkDestroyDebugUtilsMessengerEXT(instance_, utils_callbacks.back(), nullptr);
|
||||
utils_callbacks.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2) {
|
||||
winsys_ = winsys;
|
||||
winsysData1_ = data1;
|
||||
winsysData2_ = data2;
|
||||
ReinitSurface(width, height);
|
||||
return ReinitSurface();
|
||||
}
|
||||
|
||||
void VulkanContext::ReinitSurface(int width, int height) {
|
||||
VkResult VulkanContext::ReinitSurface() {
|
||||
if (surface_ != VK_NULL_HANDLE) {
|
||||
ILOG("Destroying Vulkan surface (%d, %d)", width_, height_);
|
||||
ILOG("Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height);
|
||||
vkDestroySurfaceKHR(instance_, surface_, nullptr);
|
||||
surface_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
ILOG("Creating Vulkan surface (%d, %d)", width, height);
|
||||
ILOG("Creating Vulkan surface for window");
|
||||
switch (winsys_) {
|
||||
#ifdef _WIN32
|
||||
case WINDOWSYSTEM_WIN32:
|
||||
{
|
||||
HINSTANCE connection = (HINSTANCE)winsysData1_;
|
||||
HWND window = (HWND)winsysData2_;
|
||||
|
||||
if (width < 0 || height < 0)
|
||||
{
|
||||
RECT rc;
|
||||
GetClientRect(window, &rc);
|
||||
width = rc.right - rc.left;
|
||||
height = rc.bottom - rc.top;
|
||||
}
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR win32{ VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
|
||||
win32.flags = 0;
|
||||
win32.hwnd = window;
|
||||
win32.hinstance = connection;
|
||||
VkResult res = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_);
|
||||
assert(res == VK_SUCCESS);
|
||||
break;
|
||||
win32.hwnd = (HWND)winsysData2_;
|
||||
win32.hinstance = (HINSTANCE)winsysData1_;
|
||||
return vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_);
|
||||
}
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
@@ -680,54 +759,44 @@ void VulkanContext::ReinitSurface(int width, int height) {
|
||||
VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR };
|
||||
android.flags = 0;
|
||||
android.window = wnd;
|
||||
VkResult res = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_);
|
||||
assert(res == VK_SUCCESS);
|
||||
break;
|
||||
return vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_);
|
||||
}
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||
case WINDOWSYSTEM_XLIB:
|
||||
{
|
||||
VkXlibSurfaceCreateInfoKHR xlib = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR };
|
||||
VkXlibSurfaceCreateInfoKHR xlib{ VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR };
|
||||
xlib.flags = 0;
|
||||
xlib.dpy = (Display *)winsysData1_;
|
||||
xlib.window = (Window)winsysData2_;
|
||||
VkResult res = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_);
|
||||
assert(res == VK_SUCCESS);
|
||||
break;
|
||||
return vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_);
|
||||
}
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
case WINDOWSYSTEM_XCB:
|
||||
{
|
||||
VkXCBSurfaceCreateInfoKHR xcb = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR };
|
||||
VkXCBSurfaceCreateInfoKHR xcb{ VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR };
|
||||
xcb.flags = 0;
|
||||
xcb.connection = (Connection *)winsysData1_;
|
||||
xcb.window = (Window)(uintptr_t)winsysData2_;
|
||||
VkResult res = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_);
|
||||
assert(res == VK_SUCCESS);
|
||||
break;
|
||||
return vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_);
|
||||
}
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
case WINDOWSYSTEM_WAYLAND:
|
||||
{
|
||||
VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR };
|
||||
VkWaylandSurfaceCreateInfoKHR wayland{ VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR };
|
||||
wayland.flags = 0;
|
||||
wayland.display = (wl_display *)winsysData1_;
|
||||
wayland.surface = (wl_surface *)winsysData2_;
|
||||
VkResult res = vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_);
|
||||
assert(res == VK_SUCCESS);
|
||||
break;
|
||||
return vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_);
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
_assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented");
|
||||
break;
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
||||
bool VulkanContext::InitQueue() {
|
||||
@@ -818,6 +887,14 @@ bool VulkanContext::InitQueue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int clamp(int x, int a, int b) {
|
||||
if (x < a)
|
||||
return a;
|
||||
if (x > b)
|
||||
return b;
|
||||
return x;
|
||||
}
|
||||
|
||||
bool VulkanContext::InitSwapchain() {
|
||||
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_);
|
||||
assert(res == VK_SUCCESS);
|
||||
@@ -829,19 +906,20 @@ bool VulkanContext::InitSwapchain() {
|
||||
res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, presentModes);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
VkExtent2D swapChainExtent;
|
||||
// width and height are either both -1, or both not -1.
|
||||
if (surfCapabilities_.currentExtent.width == (uint32_t)-1) {
|
||||
// If the surface size is undefined, the size is set to
|
||||
// the size of the images requested.
|
||||
ILOG("initSwapchain: %dx%d", width_, height_);
|
||||
swapChainExtent.width = width_;
|
||||
swapChainExtent.height = height_;
|
||||
} else {
|
||||
// If the surface size is defined, the swap chain size must match
|
||||
swapChainExtent = surfCapabilities_.currentExtent;
|
||||
ILOG("surfCapabilities_.currentExtent: %dx%d", surfCapabilities_.currentExtent.width, surfCapabilities_.currentExtent.height);
|
||||
ILOG("surfCapabilities_.minImageExtent: %dx%d", surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height);
|
||||
ILOG("surfCapabilities_.maxImageExtent: %dx%d", surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height);
|
||||
|
||||
swapChainExtent_.width = clamp(surfCapabilities_.currentExtent.width, surfCapabilities_.minImageExtent.width, surfCapabilities_.maxImageExtent.width);
|
||||
swapChainExtent_.height = clamp(surfCapabilities_.currentExtent.height, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.height);
|
||||
|
||||
if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) {
|
||||
// Swap chain width hack to avoid issue #11743 (PowerVR driver bug).
|
||||
swapChainExtent_.width &= ~31;
|
||||
}
|
||||
|
||||
ILOG("swapChainExtent: %dx%d", swapChainExtent_.width, swapChainExtent_.height);
|
||||
|
||||
// TODO: Find a better way to specify the prioritized present mode while being able
|
||||
// to fall back in a sensible way.
|
||||
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
|
||||
@@ -891,13 +969,13 @@ bool VulkanContext::InitSwapchain() {
|
||||
preTransform = surfCapabilities_.currentTransform;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR swap_chain_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
||||
VkSwapchainCreateInfoKHR swap_chain_info{ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
||||
swap_chain_info.surface = surface_;
|
||||
swap_chain_info.minImageCount = desiredNumberOfSwapChainImages;
|
||||
swap_chain_info.imageFormat = swapchainFormat_;
|
||||
swap_chain_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
|
||||
swap_chain_info.imageExtent.width = swapChainExtent.width;
|
||||
swap_chain_info.imageExtent.height = swapChainExtent.height;
|
||||
swap_chain_info.imageExtent.width = swapChainExtent_.width;
|
||||
swap_chain_info.imageExtent.height = swapChainExtent_.height;
|
||||
swap_chain_info.preTransform = preTransform;
|
||||
swap_chain_info.imageArrayLayers = 1;
|
||||
swap_chain_info.presentMode = swapchainPresentMode;
|
||||
@@ -1241,3 +1319,24 @@ void VulkanDeleteList::PerformDeletes(VkDevice device) {
|
||||
}
|
||||
descSetLayouts_.clear();
|
||||
}
|
||||
|
||||
void VulkanContext::GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation) {
|
||||
if (DeviceExtensions().KHR_dedicated_allocation) {
|
||||
VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR};
|
||||
memReqInfo2.image = image;
|
||||
|
||||
VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR};
|
||||
VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR};
|
||||
memReq2.pNext = &memDedicatedReq;
|
||||
|
||||
vkGetImageMemoryRequirements2KHR(GetDevice(), &memReqInfo2, &memReq2);
|
||||
|
||||
*mem_reqs = memReq2.memoryRequirements;
|
||||
*dedicatedAllocation =
|
||||
(memDedicatedReq.requiresDedicatedAllocation != VK_FALSE) ||
|
||||
(memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
|
||||
} else {
|
||||
vkGetImageMemoryRequirements(GetDevice(), image, mem_reqs);
|
||||
*dedicatedAllocation = false;
|
||||
}
|
||||
}
|
||||
@@ -101,11 +101,6 @@ private:
|
||||
std::vector<Callback> callbacks_;
|
||||
};
|
||||
|
||||
// For fast extension-enabled checks.
|
||||
struct VulkanDeviceExtensions {
|
||||
bool DEDICATED_ALLOCATION;
|
||||
};
|
||||
|
||||
// Useful for debugging on ARM Mali. This eliminates transaction elimination
|
||||
// which can cause artifacts if you get barriers wrong (or if there are driver bugs).
|
||||
// Cost is reduced performance on some GPU architectures.
|
||||
@@ -142,8 +137,9 @@ public:
|
||||
VulkanDeleteList &Delete() { return globalDeleteList_; }
|
||||
|
||||
// The parameters are whatever the chosen window system wants.
|
||||
void InitSurface(WindowSystem winsys, void *data1, void *data2, int width = -1, int height = -1);
|
||||
void ReinitSurface(int width = -1, int height = -1);
|
||||
// The extents will be automatically determined.
|
||||
VkResult InitSurface(WindowSystem winsys, void *data1, void *data2);
|
||||
VkResult ReinitSurface();
|
||||
|
||||
bool InitQueue();
|
||||
bool InitObjects();
|
||||
@@ -160,15 +156,19 @@ public:
|
||||
VkFence CreateFence(bool presignalled);
|
||||
bool CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule);
|
||||
|
||||
int GetBackbufferWidth() { return width_; }
|
||||
int GetBackbufferHeight() { return height_; }
|
||||
int GetBackbufferWidth() { return (int)swapChainExtent_.width; }
|
||||
int GetBackbufferHeight() { return (int)swapChainExtent_.height; }
|
||||
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
|
||||
VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata = nullptr);
|
||||
VkResult InitDebugUtilsCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback, int bits, void *userdata);
|
||||
void DestroyDebugUtilsCallback();
|
||||
|
||||
// Legacy reporting
|
||||
VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata);
|
||||
void DestroyDebugMsgCallback();
|
||||
|
||||
VkPhysicalDevice GetPhysicalDevice(int n = 0) const {
|
||||
@@ -189,7 +189,15 @@ public:
|
||||
return graphics_queue_family_index_;
|
||||
}
|
||||
|
||||
const VkPhysicalDeviceProperties &GetPhysicalDeviceProperties(int i) const {
|
||||
struct PhysicalDeviceProps {
|
||||
VkPhysicalDeviceProperties properties;
|
||||
VkPhysicalDevicePushDescriptorPropertiesKHR pushDescriptorProperties;
|
||||
VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProperties;
|
||||
};
|
||||
|
||||
const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const {
|
||||
if (i < 0)
|
||||
i = GetCurrentPhysicalDevice();
|
||||
return physicalDeviceProperties_[i];
|
||||
}
|
||||
|
||||
@@ -205,8 +213,13 @@ public:
|
||||
const std::vector<const char *> &GetDeviceExtensionsEnabled() const {
|
||||
return device_extensions_enabled_;
|
||||
}
|
||||
const VkPhysicalDeviceFeatures &GetFeaturesAvailable() const { return featuresAvailable_; }
|
||||
const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; }
|
||||
|
||||
struct PhysicalDeviceFeatures {
|
||||
VkPhysicalDeviceFeatures available{};
|
||||
VkPhysicalDeviceFeatures enabled{};
|
||||
};
|
||||
|
||||
const PhysicalDeviceFeatures &GetDeviceFeatures() const { return deviceFeatures_; }
|
||||
const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; }
|
||||
const VkSurfaceCapabilitiesKHR &GetSurfaceCapabilities() const { return surfCapabilities_; }
|
||||
|
||||
@@ -247,7 +260,9 @@ public:
|
||||
MAX_INFLIGHT_FRAMES = 3,
|
||||
};
|
||||
|
||||
const VulkanDeviceExtensions &DeviceExtensions() { return deviceExtensionsLookup_; }
|
||||
const VulkanDeviceExtensions &DeviceExtensions() { return extensionsLookup_; }
|
||||
|
||||
void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation);
|
||||
|
||||
private:
|
||||
// A layer can expose extensions, keep track of those extensions here.
|
||||
@@ -281,23 +296,23 @@ private:
|
||||
|
||||
std::vector<const char *> device_extensions_enabled_;
|
||||
std::vector<VkExtensionProperties> device_extension_properties_;
|
||||
VulkanDeviceExtensions deviceExtensionsLookup_{};
|
||||
VulkanDeviceExtensions extensionsLookup_{};
|
||||
|
||||
std::vector<VkPhysicalDevice> physical_devices_;
|
||||
|
||||
int physical_device_ = -1;
|
||||
|
||||
uint32_t graphics_queue_family_index_ = -1;
|
||||
std::vector<VkPhysicalDeviceProperties> physicalDeviceProperties_{};
|
||||
std::vector<PhysicalDeviceProps> physicalDeviceProperties_{};
|
||||
std::vector<VkQueueFamilyProperties> queue_props;
|
||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||
|
||||
// Custom collection of things that are good to know
|
||||
VulkanPhysicalDeviceInfo deviceInfo_{};
|
||||
|
||||
// Swap chain
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
// Swap chain extent
|
||||
VkExtent2D swapChainExtent_{};
|
||||
|
||||
int flags_ = 0;
|
||||
|
||||
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
|
||||
@@ -314,14 +329,14 @@ private:
|
||||
VulkanDeleteList globalDeleteList_;
|
||||
|
||||
std::vector<VkDebugReportCallbackEXT> msg_callbacks;
|
||||
std::vector<VkDebugUtilsMessengerEXT> utils_callbacks;
|
||||
|
||||
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
|
||||
VkFormat swapchainFormat_;
|
||||
|
||||
uint32_t queue_count = 0;
|
||||
|
||||
VkPhysicalDeviceFeatures featuresAvailable_{};
|
||||
VkPhysicalDeviceFeatures featuresEnabled_{};
|
||||
PhysicalDeviceFeatures deviceFeatures_;
|
||||
|
||||
VkSurfaceCapabilitiesKHR surfCapabilities_{};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ const char *ObjTypeToString(VkDebugReportObjectTypeEXT type) {
|
||||
}
|
||||
}
|
||||
|
||||
VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData) {
|
||||
VkBool32 VKAPI_CALL VulkanDebugReportCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData) {
|
||||
const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData;
|
||||
std::ostringstream message;
|
||||
|
||||
@@ -73,8 +73,6 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje
|
||||
}
|
||||
message << "[" << pLayerPrefix << "] " << ObjTypeToString(objType) << " Code " << msgCode << " : " << pMsg << "\n";
|
||||
|
||||
if (msgCode == 2) // Useless perf warning ("Vertex attribute at location X not consumed by vertex shader")
|
||||
return false;
|
||||
if (msgCode == 64) // Another useless perf warning that will be seen less and less as we optimize - vkCmdClearAttachments() issued on command buffer object 0x00000195296C6D40 prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.
|
||||
return false;
|
||||
if (msgCode == 5)
|
||||
@@ -105,3 +103,59 @@ VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObje
|
||||
// keep that behavior here.
|
||||
return false;
|
||||
}
|
||||
|
||||
VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData) {
|
||||
const VulkanLogOptions *options = (const VulkanLogOptions *)pUserData;
|
||||
std::ostringstream message;
|
||||
|
||||
const char *pMessage = pCallbackData->pMessage;
|
||||
int messageCode = pCallbackData->messageIdNumber;
|
||||
const char *pLayerPrefix = "";
|
||||
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
message << "ERROR(";
|
||||
} else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
|
||||
message << "WARNING(";
|
||||
} else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
|
||||
message << "INFO(";
|
||||
} else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
|
||||
message << "VERBOSE(";
|
||||
}
|
||||
|
||||
if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
|
||||
message << "perf";
|
||||
} else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
|
||||
message << "general";
|
||||
} else if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
|
||||
message << "validation";
|
||||
}
|
||||
message << ":" << pCallbackData->messageIdNumber << ") " << pMessage << "\n";
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string msg = message.str();
|
||||
OutputDebugStringA(msg.c_str());
|
||||
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
if (options->breakOnError && IsDebuggerPresent()) {
|
||||
DebugBreak();
|
||||
}
|
||||
if (options->msgBoxOnError) {
|
||||
MessageBoxA(NULL, pMessage, "Alert", MB_OK);
|
||||
}
|
||||
} else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
|
||||
// Don't break on perf warnings for now, even with a debugger. We log them at least.
|
||||
if (options->breakOnWarning && IsDebuggerPresent() && 0 == (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) {
|
||||
DebugBreak();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// false indicates that layer should not bail-out of an
|
||||
// API call that had validation failures. This may mean that the
|
||||
// app dies inside the driver due to invalid parameter(s).
|
||||
// That's what would happen without validation layers, so we'll
|
||||
// keep that behavior here.
|
||||
return false;
|
||||
}
|
||||
@@ -25,4 +25,5 @@ struct VulkanLogOptions {
|
||||
bool msgBoxOnError;
|
||||
};
|
||||
|
||||
VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData);
|
||||
VkBool32 VKAPI_CALL VulkanDebugReportCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void *pUserData);
|
||||
VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData);
|
||||
@@ -67,15 +67,19 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image_);
|
||||
if (res != VK_SUCCESS) {
|
||||
_assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
||||
ELOG("vkCreateImage failed: %s", VulkanResultToString(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryRequirements mem_reqs{};
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image_, &mem_reqs);
|
||||
bool dedicatedAllocation = false;
|
||||
vulkan_->GetImageMemoryRequirements(image_, &mem_reqs, &dedicatedAllocation);
|
||||
|
||||
if (allocator_) {
|
||||
if (allocator_ && !dedicatedAllocation) {
|
||||
offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag());
|
||||
if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) {
|
||||
ELOG("Image memory allocation failed (mem_reqs.size=%d, typebits=%08x", (int)mem_reqs.size, (int)mem_reqs.memoryTypeBits);
|
||||
// Destructor will take care of the image.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -83,16 +87,21 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
|
||||
if (dedicatedAllocation) {
|
||||
dedicatedAllocateInfo.image = image_;
|
||||
mem_alloc.pNext = &dedicatedAllocateInfo;
|
||||
}
|
||||
|
||||
// Find memory type - don't specify any mapping requirements
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
_assert_(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem_);
|
||||
if (res != VK_SUCCESS) {
|
||||
ELOG("vkAllocateMemory failed: %s", VulkanResultToString(res));
|
||||
_assert_msg_(G3D, res != VK_ERROR_TOO_MANY_OBJECTS, "Too many Vulkan memory objects!");
|
||||
_assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
||||
vkDestroyImage(vulkan_->GetDevice(), image_, nullptr);
|
||||
image_ = VK_NULL_HANDLE;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -101,6 +110,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), image_, mem_, offset_);
|
||||
if (res != VK_SUCCESS) {
|
||||
ELOG("vkBindImageMemory failed: %s", VulkanResultToString(res));
|
||||
// This leaks the image and memory. Should not really happen though...
|
||||
_assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
||||
return false;
|
||||
@@ -144,6 +154,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
|
||||
|
||||
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view_);
|
||||
if (res != VK_SUCCESS) {
|
||||
ELOG("vkCreateImageView failed: %s", VulkanResultToString(res));
|
||||
// This leaks the image.
|
||||
_assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
||||
return false;
|
||||
|
||||
@@ -193,9 +193,22 @@ PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
|
||||
// And the DEBUG_REPORT extension. We dynamically load this.
|
||||
PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT;
|
||||
PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT;
|
||||
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
|
||||
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
|
||||
|
||||
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
|
||||
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
|
||||
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
|
||||
PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT;
|
||||
PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
|
||||
PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
|
||||
|
||||
PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT;
|
||||
PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
|
||||
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
||||
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
|
||||
PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
|
||||
|
||||
#ifdef _WIN32
|
||||
static HINSTANCE vulkanLibrary;
|
||||
@@ -246,6 +259,7 @@ bool VulkanMayBeAvailable() {
|
||||
|
||||
// Do a hyper minimal initialization and teardown to figure out if there's any chance
|
||||
// that any sort of Vulkan will be usable.
|
||||
PFN_vkEnumerateInstanceExtensionProperties localEnumerateInstanceExtensionProperties = LOAD_GLOBAL_FUNC_LOCAL(lib, vkEnumerateInstanceExtensionProperties);
|
||||
PFN_vkCreateInstance localCreateInstance = LOAD_GLOBAL_FUNC_LOCAL(lib, vkCreateInstance);
|
||||
PFN_vkEnumeratePhysicalDevices localEnumerate = LOAD_GLOBAL_FUNC_LOCAL(lib, vkEnumeratePhysicalDevices);
|
||||
PFN_vkDestroyInstance localDestroyInstance = LOAD_GLOBAL_FUNC_LOCAL(lib, vkDestroyInstance);
|
||||
@@ -256,22 +270,60 @@ bool VulkanMayBeAvailable() {
|
||||
VkApplicationInfo info{ VK_STRUCTURE_TYPE_APPLICATION_INFO };
|
||||
std::vector<VkPhysicalDevice> devices;
|
||||
bool anyGood = false;
|
||||
const char *instanceExtensions[1]{};
|
||||
const char *instanceExtensions[2]{};
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
VkResult res;
|
||||
uint32_t physicalDeviceCount = 0;
|
||||
|
||||
if (!localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties)
|
||||
goto bail;
|
||||
uint32_t instanceExtCount = 1;
|
||||
bool surfaceExtensionFound = false;
|
||||
bool platformSurfaceExtensionFound = false;
|
||||
std::vector<VkExtensionProperties> instanceExts;
|
||||
instanceExtensions[ci.enabledExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
|
||||
|
||||
#ifdef _WIN32
|
||||
instanceExtensions[0] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
|
||||
ci.enabledExtensionCount = 1;
|
||||
const char * const platformSurfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
|
||||
#elif defined(__ANDROID__)
|
||||
instanceExtensions[0] = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
|
||||
ci.enabledExtensionCount = 1;
|
||||
const char *platformSurfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
|
||||
#else
|
||||
const char *platformSurfaceExtension = 0;
|
||||
#endif
|
||||
|
||||
if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties)
|
||||
goto bail;
|
||||
|
||||
res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr);
|
||||
// Maximum paranoia.
|
||||
if (res != VK_SUCCESS) {
|
||||
ELOG("Enumerating VK extensions failed.");
|
||||
goto bail;
|
||||
}
|
||||
if (instanceExtCount == 0) {
|
||||
ELOG("No VK instance extensions - won't be able to present.");
|
||||
goto bail;
|
||||
}
|
||||
instanceExts.resize(instanceExtCount);
|
||||
res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data());
|
||||
if (res != VK_SUCCESS) {
|
||||
ELOG("Enumerating VK extensions failed.");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (platformSurfaceExtension) {
|
||||
for (auto iter : instanceExts) {
|
||||
if (!strcmp(iter.extensionName, platformSurfaceExtension)) {
|
||||
instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension;
|
||||
platformSurfaceExtensionFound = true;
|
||||
break;
|
||||
} else if (!strcmp(iter.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
|
||||
surfaceExtensionFound = true;
|
||||
}
|
||||
}
|
||||
if (!platformSurfaceExtensionFound || !surfaceExtensionFound) {
|
||||
ELOG("Platform surface extension not found");
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
ci.ppEnabledExtensionNames = instanceExtensions;
|
||||
ci.enabledLayerCount = 0;
|
||||
info.apiVersion = VK_API_VERSION_1_0;
|
||||
@@ -372,7 +424,7 @@ bool VulkanLoad() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance) {
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions) {
|
||||
// OK, let's use the above functions to get the rest.
|
||||
LOAD_INSTANCE_FUNC(instance, vkDestroyInstance);
|
||||
LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices);
|
||||
@@ -532,8 +584,25 @@ void VulkanLoadInstanceFunctions(VkInstance instance) {
|
||||
|
||||
LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR);
|
||||
|
||||
dyn_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
|
||||
dyn_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
|
||||
if (enabledExtensions.KHR_get_physical_device_properties2) {
|
||||
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR);
|
||||
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR);
|
||||
}
|
||||
|
||||
if (enabledExtensions.EXT_debug_report) {
|
||||
LOAD_INSTANCE_FUNC(instance, vkCreateDebugReportCallbackEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkDestroyDebugReportCallbackEXT);
|
||||
}
|
||||
|
||||
if (enabledExtensions.EXT_debug_utils) {
|
||||
LOAD_INSTANCE_FUNC(instance, vkCreateDebugUtilsMessengerEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkDestroyDebugUtilsMessengerEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkCmdBeginDebugUtilsLabelEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkCmdEndDebugUtilsLabelEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkCmdInsertDebugUtilsLabelEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectNameEXT);
|
||||
LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectTagEXT);
|
||||
}
|
||||
|
||||
WLOG("Vulkan instance functions loaded.");
|
||||
}
|
||||
@@ -541,7 +610,7 @@ void VulkanLoadInstanceFunctions(VkInstance instance) {
|
||||
// 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.
|
||||
void VulkanLoadDeviceFunctions(VkDevice device) {
|
||||
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions) {
|
||||
WLOG("Vulkan device functions loaded.");
|
||||
// TODO: Move more functions VulkanLoadInstanceFunctions to here.
|
||||
LOAD_DEVICE_FUNC(device, vkCreateSwapchainKHR);
|
||||
@@ -549,6 +618,13 @@ void VulkanLoadDeviceFunctions(VkDevice device) {
|
||||
LOAD_DEVICE_FUNC(device, vkGetSwapchainImagesKHR);
|
||||
LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR);
|
||||
LOAD_DEVICE_FUNC(device, vkQueuePresentKHR);
|
||||
if (enabledExtensions.EXT_external_memory_host) {
|
||||
LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT);
|
||||
}
|
||||
if (enabledExtensions.KHR_dedicated_allocation) {
|
||||
LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR);
|
||||
LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanFree() {
|
||||
|
||||
@@ -197,15 +197,48 @@ extern PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
|
||||
// And the DEBUG_REPORT extension. Since we load this dynamically even in static
|
||||
// linked mode, we have to rename it :(
|
||||
extern PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT;
|
||||
extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT;
|
||||
extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
|
||||
extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
|
||||
|
||||
extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
|
||||
extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
|
||||
extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
|
||||
extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
|
||||
extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT;
|
||||
extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
|
||||
extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
|
||||
|
||||
// Assorted other extensions.
|
||||
extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
|
||||
extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
||||
extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT;
|
||||
extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
|
||||
extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
|
||||
|
||||
|
||||
// For fast extension-enabled checks.
|
||||
struct VulkanDeviceExtensions {
|
||||
bool EXT_debug_report;
|
||||
bool EXT_debug_utils;
|
||||
bool KHR_maintenance1; // required for KHR_create_renderpass2
|
||||
bool KHR_maintenance2;
|
||||
bool KHR_maintenance3;
|
||||
bool KHR_multiview; // required for KHR_create_renderpass2
|
||||
bool KHR_get_memory_requirements2;
|
||||
bool KHR_dedicated_allocation;
|
||||
bool KHR_create_renderpass2;
|
||||
bool EXT_external_memory_host;
|
||||
bool KHR_get_physical_device_properties2;
|
||||
bool KHR_depth_stencil_resolve;
|
||||
bool EXT_shader_stencil_export;
|
||||
// bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers.
|
||||
};
|
||||
|
||||
// Way to do a quick check before even attempting to load.
|
||||
bool VulkanMayBeAvailable();
|
||||
void VulkanSetAvailable(bool available);
|
||||
|
||||
bool VulkanLoad();
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance);
|
||||
void VulkanLoadDeviceFunctions(VkDevice device);
|
||||
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions);
|
||||
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions);
|
||||
void VulkanFree();
|
||||
@@ -191,14 +191,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic
|
||||
assert(!destroyed_);
|
||||
uint32_t memoryTypeIndex;
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex);
|
||||
assert(pass);
|
||||
if (!pass) {
|
||||
return ALLOCATE_FAILED;
|
||||
}
|
||||
if (memoryTypeIndex_ == UNDEFINED_MEMORY_TYPE) {
|
||||
memoryTypeIndex_ = memoryTypeIndex;
|
||||
} else if (memoryTypeIndex_ != memoryTypeIndex) {
|
||||
assert(memoryTypeIndex_ == memoryTypeIndex);
|
||||
ELOG("Failed to pick an appropriate memory type (req: %08x)", reqs.memoryTypeBits);
|
||||
return ALLOCATE_FAILED;
|
||||
}
|
||||
|
||||
@@ -213,6 +207,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic
|
||||
// This helps us "creep forward", and also spend less time allocating.
|
||||
const size_t actualSlab = (lastSlab_ + i) % numSlabs;
|
||||
Slab &slab = slabs_[actualSlab];
|
||||
if (slab.memoryTypeIndex != memoryTypeIndex)
|
||||
continue;
|
||||
size_t start = slab.nextFree;
|
||||
|
||||
while (start < slab.usage.size()) {
|
||||
@@ -227,7 +223,7 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic
|
||||
}
|
||||
|
||||
// Okay, we couldn't fit it into any existing slabs. We need a new one.
|
||||
if (!AllocateSlab(size)) {
|
||||
if (!AllocateSlab(size, memoryTypeIndex)) {
|
||||
return ALLOCATE_FAILED;
|
||||
}
|
||||
|
||||
@@ -401,16 +397,17 @@ void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) {
|
||||
delete userdata;
|
||||
}
|
||||
|
||||
bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) {
|
||||
bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex) {
|
||||
assert(!destroyed_);
|
||||
if (!slabs_.empty() && minSlabSize_ < maxSlabSize_) {
|
||||
// We're allocating an additional slab, so rachet up its size.
|
||||
// TODO: Maybe should not do this when we are allocating a new slab due to memoryTypeIndex not matching?
|
||||
minSlabSize_ <<= 1;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
alloc.allocationSize = minSlabSize_;
|
||||
alloc.memoryTypeIndex = memoryTypeIndex_;
|
||||
alloc.memoryTypeIndex = memoryTypeIndex;
|
||||
|
||||
while (alloc.allocationSize < minBytes) {
|
||||
alloc.allocationSize <<= 1;
|
||||
@@ -427,6 +424,7 @@ bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) {
|
||||
|
||||
slabs_.resize(slabs_.size() + 1);
|
||||
Slab &slab = slabs_[slabs_.size() - 1];
|
||||
slab.memoryTypeIndex = memoryTypeIndex;
|
||||
slab.deviceMemory = deviceMemory;
|
||||
slab.usage.resize((size_t)(alloc.allocationSize >> SLAB_GRAIN_SHIFT));
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ private:
|
||||
|
||||
struct Slab {
|
||||
VkDeviceMemory deviceMemory;
|
||||
uint32_t memoryTypeIndex = UNDEFINED_MEMORY_TYPE;
|
||||
std::vector<uint8_t> usage;
|
||||
std::unordered_map<size_t, size_t> allocSizes;
|
||||
std::unordered_map<size_t, UsageInfo> tags;
|
||||
@@ -200,7 +201,7 @@ private:
|
||||
freeInfo->allocator->ExecuteFree(freeInfo); // this deletes freeInfo
|
||||
}
|
||||
|
||||
bool AllocateSlab(VkDeviceSize minBytes);
|
||||
bool AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex);
|
||||
bool AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const std::string &tag);
|
||||
void Decimate();
|
||||
void DoTouch(VkDeviceMemory deviceMemory, size_t offset);
|
||||
@@ -212,6 +213,5 @@ private:
|
||||
size_t lastSlab_ = 0;
|
||||
size_t minSlabSize_;
|
||||
const size_t maxSlabSize_;
|
||||
uint32_t memoryTypeIndex_ = UNDEFINED_MEMORY_TYPE;
|
||||
bool destroyed_ = false;
|
||||
};
|
||||
@@ -69,6 +69,10 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
|
||||
CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack);
|
||||
CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack);
|
||||
CheckSetting(iniFile, gameID, "AdhocHackDisableNBSwitch", &flags_.AdhocHackDisableNBSwitch);
|
||||
CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB);
|
||||
CheckSetting(iniFile, gameID, "YugiohSaveFix", &flags_.YugiohSaveFix);
|
||||
CheckSetting(iniFile, gameID, "ForceUMDDelay", &flags_.ForceUMDDelay);
|
||||
CheckSetting(iniFile, gameID, "ForceMax60FPS", &flags_.ForceMax60FPS);
|
||||
}
|
||||
|
||||
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {
|
||||
|
||||
@@ -69,6 +69,10 @@ struct CompatFlags {
|
||||
bool MGS2AcidHack;
|
||||
bool SonicRivalsHack;
|
||||
bool AdhocHackDisableNBSwitch;
|
||||
bool BlockTransferAllowCreateFB;
|
||||
bool YugiohSaveFix;
|
||||
bool ForceUMDDelay;
|
||||
bool ForceMax60FPS;
|
||||
};
|
||||
|
||||
class IniFile;
|
||||
|
||||
+3
-10
@@ -474,6 +474,7 @@ static ConfigSetting cpuSettings[] = {
|
||||
ConfigSetting("HideSlowWarnings", &g_Config.bHideSlowWarnings, true, true, false),
|
||||
ConfigSetting("HideStateWarnings", &g_Config.bHideStateWarnings, false, true, false),
|
||||
ConfigSetting("PreloadFunctions", &g_Config.bPreloadFunctions, false, true, true),
|
||||
ConfigSetting("JitDisableFlags", &g_Config.uJitDisableFlags, (uint32_t)0, true, true),
|
||||
ReportedConfigSetting("CPUSpeed", &g_Config.iLockedCPUSpeed, 0, true, true),
|
||||
|
||||
ConfigSetting(false),
|
||||
@@ -543,12 +544,6 @@ static int DefaultAndroidHwScale() {
|
||||
}
|
||||
|
||||
static int DefaultGPUBackend() {
|
||||
#if PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID)
|
||||
// Where supported, let's use Vulkan.
|
||||
if (VulkanMayBeAvailable()) {
|
||||
return (int)GPUBackend::VULKAN;
|
||||
}
|
||||
#endif
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
// If no Vulkan, use Direct3D 11 on Windows 8+ (most importantly 10.)
|
||||
if (DoesVersionMatchWindows(6, 2, 0, 0, true)) {
|
||||
@@ -617,6 +612,7 @@ static ConfigSetting graphicsSettings[] = {
|
||||
#ifdef _WIN32
|
||||
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
|
||||
#endif
|
||||
ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false),
|
||||
ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode, true, true),
|
||||
ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true),
|
||||
ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true),
|
||||
@@ -628,6 +624,7 @@ static ConfigSetting graphicsSettings[] = {
|
||||
ReportedConfigSetting("AndroidHwScale", &g_Config.iAndroidHwScale, &DefaultAndroidHwScale),
|
||||
ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true),
|
||||
ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true),
|
||||
ReportedConfigSetting("FrameSkipType", &g_Config.iFrameSkipType, 0, true, true),
|
||||
ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true),
|
||||
ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true),
|
||||
ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true),
|
||||
@@ -635,7 +632,6 @@ static ConfigSetting graphicsSettings[] = {
|
||||
#if defined(USING_WIN_UI)
|
||||
ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false),
|
||||
#endif
|
||||
ReportedConfigSetting("ForceMaxEmulatedFPS", &g_Config.iForceMaxEmulatedFPS, 60, true, true),
|
||||
ConfigSetting("RefreshAt60Hz", &g_Config.bRefreshAt60Hz, false, true, true),
|
||||
|
||||
// Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine.
|
||||
@@ -659,7 +655,6 @@ static ConfigSetting graphicsSettings[] = {
|
||||
ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true),
|
||||
ConfigSetting("MipMap", &g_Config.bMipMap, true, true, true),
|
||||
|
||||
ReportedConfigSetting("TrueColor", &g_Config.bTrueColor, true, true, true),
|
||||
ReportedConfigSetting("ReplaceTextures", &g_Config.bReplaceTextures, true, true, true),
|
||||
ReportedConfigSetting("SaveNewTextures", &g_Config.bSaveNewTextures, false, true, true),
|
||||
ReportedConfigSetting("IgnoreTextureFilenames", &g_Config.bIgnoreTextureFilenames, true, true, false),
|
||||
@@ -669,11 +664,9 @@ static ConfigSetting graphicsSettings[] = {
|
||||
ReportedConfigSetting("TexDeposterize", &g_Config.bTexDeposterize, false, true, true),
|
||||
ReportedConfigSetting("TexRealtime", &g_Config.bRealtimeTexScaling, false, true, true),
|
||||
ConfigSetting("VSyncInterval", &g_Config.bVSync, true, true, true),
|
||||
ReportedConfigSetting("DisableStencilTest", &g_Config.bDisableStencilTest, false, true, true),
|
||||
ReportedConfigSetting("BloomHack", &g_Config.iBloomHack, 2, true, true),
|
||||
|
||||
// Not really a graphics setting...
|
||||
ReportedConfigSetting("TimerHack", &g_Config.bTimerHack, &DefaultTimerHack, true, true),
|
||||
ReportedConfigSetting("SplineBezierQuality", &g_Config.iSplineBezierQuality, 2, true, true),
|
||||
ReportedConfigSetting("HardwareTessellation", &g_Config.bHardwareTessellation, false, true, true),
|
||||
ReportedConfigSetting("PostShader", &g_Config.sPostShaderName, "Off", true, true),
|
||||
|
||||
+3
-2
@@ -98,6 +98,7 @@ public:
|
||||
bool bHideSlowWarnings;
|
||||
bool bHideStateWarnings;
|
||||
bool bPreloadFunctions;
|
||||
uint32_t uJitDisableFlags;
|
||||
|
||||
bool bVulkanMultithreading;
|
||||
bool bSeparateSASThread;
|
||||
@@ -139,6 +140,7 @@ public:
|
||||
bool bHardwareTransform; // only used in the GLES backend
|
||||
bool bSoftwareSkinning; // may speed up some games
|
||||
bool bShaderDepal;
|
||||
bool bVendorBugChecksEnabled;
|
||||
|
||||
int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering
|
||||
int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG)
|
||||
@@ -151,6 +153,7 @@ public:
|
||||
bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations.
|
||||
bool bVSync;
|
||||
int iFrameSkip;
|
||||
int iFrameSkipType;
|
||||
bool bAutoFrameSkip;
|
||||
bool bFrameSkipUnthrottle;
|
||||
|
||||
@@ -194,9 +197,7 @@ public:
|
||||
bool bEnableCheats;
|
||||
bool bReloadCheats;
|
||||
int iCwCheatRefreshRate;
|
||||
bool bDisableStencilTest;
|
||||
int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive
|
||||
bool bTimerHack;
|
||||
bool bBlockTransferGPU;
|
||||
bool bDisableSlowFramebufEffects;
|
||||
bool bFragmentTestCache;
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<ForcedIncludeFiles>Common/DbgNew.h</ForcedIncludeFiles>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -101,6 +102,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<ForcedIncludeFiles>Common/DbgNew.h</ForcedIncludeFiles>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
||||
@@ -120,15 +120,8 @@ u64 GetGlobalTimeUsScaled()
|
||||
{
|
||||
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
|
||||
int freq = GetClockFrequencyMHz();
|
||||
if (g_Config.bTimerHack) {
|
||||
float vps;
|
||||
__DisplayGetVPS(&vps);
|
||||
if (vps > 4.0f)
|
||||
freq *= (vps / (g_Config.bRefreshAt60Hz ? 60.0f : 59.94f));
|
||||
}
|
||||
s64 usSinceLast = ticksSinceLast / freq;
|
||||
return lastGlobalTimeUs + usSinceLast;
|
||||
|
||||
}
|
||||
|
||||
u64 GetGlobalTimeUs()
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
#include "net/websocket_server.h"
|
||||
#include "Common/Log.h"
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
// Enum name overlapped with UWP macro, quick hack to disable it
|
||||
#undef OPTIONAL
|
||||
#endif
|
||||
|
||||
using namespace json;
|
||||
|
||||
static inline void DebuggerJsonAddTicket(JsonWriter &writer, const JsonGet &data) {
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
// Takes ownership of backend.
|
||||
CachingFileLoader::CachingFileLoader(FileLoader *backend)
|
||||
: backend_(backend) {
|
||||
: ProxiedFileLoader(backend) {
|
||||
}
|
||||
|
||||
void CachingFileLoader::Prepare() {
|
||||
std::call_once(preparedFlag_, [this](){
|
||||
filesize_ = backend_->FileSize();
|
||||
filesize_ = ProxiedFileLoader::FileSize();
|
||||
if (filesize_ > 0) {
|
||||
InitCache();
|
||||
}
|
||||
@@ -41,27 +41,25 @@ CachingFileLoader::~CachingFileLoader() {
|
||||
if (filesize_ > 0) {
|
||||
ShutdownCache();
|
||||
}
|
||||
// Takes ownership.
|
||||
delete backend_;
|
||||
}
|
||||
|
||||
bool CachingFileLoader::Exists() {
|
||||
if (exists_ == -1) {
|
||||
exists_ = backend_->Exists() ? 1 : 0;
|
||||
exists_ = ProxiedFileLoader::Exists() ? 1 : 0;
|
||||
}
|
||||
return exists_ == 1;
|
||||
}
|
||||
|
||||
bool CachingFileLoader::ExistsFast() {
|
||||
if (exists_ == -1) {
|
||||
return backend_->ExistsFast();
|
||||
return ProxiedFileLoader::ExistsFast();
|
||||
}
|
||||
return exists_ == 1;
|
||||
}
|
||||
|
||||
bool CachingFileLoader::IsDirectory() {
|
||||
if (isDirectory_ == -1) {
|
||||
isDirectory_ = backend_->IsDirectory() ? 1 : 0;
|
||||
isDirectory_ = ProxiedFileLoader::IsDirectory() ? 1 : 0;
|
||||
}
|
||||
return isDirectory_ == 1;
|
||||
}
|
||||
@@ -71,10 +69,6 @@ s64 CachingFileLoader::FileSize() {
|
||||
return filesize_;
|
||||
}
|
||||
|
||||
std::string CachingFileLoader::Path() const {
|
||||
return backend_->Path();
|
||||
}
|
||||
|
||||
size_t CachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) {
|
||||
Prepare();
|
||||
if (absolutePos >= filesize_) {
|
||||
@@ -288,11 +282,3 @@ void CachingFileLoader::StartReadAhead(s64 pos) {
|
||||
});
|
||||
th.detach();
|
||||
}
|
||||
|
||||
bool CachingFileLoader::IsRemote() {
|
||||
return backend_->IsRemote();
|
||||
}
|
||||
|
||||
void CachingFileLoader::Cancel() {
|
||||
backend_->Cancel();
|
||||
}
|
||||
@@ -23,25 +23,21 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/Loaders.h"
|
||||
|
||||
class CachingFileLoader : public FileLoader {
|
||||
class CachingFileLoader : public ProxiedFileLoader {
|
||||
public:
|
||||
CachingFileLoader(FileLoader *backend);
|
||||
~CachingFileLoader() override;
|
||||
|
||||
bool IsRemote() override;
|
||||
bool Exists() override;
|
||||
bool ExistsFast() override;
|
||||
bool IsDirectory() override;
|
||||
s64 FileSize() override;
|
||||
std::string Path() const override;
|
||||
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
|
||||
return ReadAt(absolutePos, bytes * count, data, flags) / bytes;
|
||||
}
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||
|
||||
void Cancel() override;
|
||||
|
||||
private:
|
||||
void Prepare();
|
||||
void InitCache();
|
||||
@@ -61,7 +57,6 @@ private:
|
||||
};
|
||||
|
||||
s64 filesize_ = 0;
|
||||
FileLoader *backend_;
|
||||
int exists_ = -1;
|
||||
int isDirectory_ = -1;
|
||||
u64 generation_;
|
||||
|
||||
@@ -41,12 +41,12 @@ std::mutex DiskCachingFileLoader::cachesMutex_;
|
||||
|
||||
// Takes ownership of backend.
|
||||
DiskCachingFileLoader::DiskCachingFileLoader(FileLoader *backend)
|
||||
: backend_(backend) {
|
||||
: ProxiedFileLoader(backend) {
|
||||
}
|
||||
|
||||
void DiskCachingFileLoader::Prepare() {
|
||||
std::call_once(preparedFlag_, [this]() {
|
||||
filesize_ = backend_->FileSize();
|
||||
filesize_ = ProxiedFileLoader::FileSize();
|
||||
if (filesize_ > 0) {
|
||||
InitCache();
|
||||
}
|
||||
@@ -57,13 +57,11 @@ DiskCachingFileLoader::~DiskCachingFileLoader() {
|
||||
if (filesize_ > 0) {
|
||||
ShutdownCache();
|
||||
}
|
||||
// Takes ownership.
|
||||
delete backend_;
|
||||
}
|
||||
|
||||
bool DiskCachingFileLoader::Exists() {
|
||||
Prepare();
|
||||
return backend_->Exists();
|
||||
return ProxiedFileLoader::Exists();
|
||||
}
|
||||
|
||||
bool DiskCachingFileLoader::ExistsFast() {
|
||||
@@ -72,19 +70,11 @@ bool DiskCachingFileLoader::ExistsFast() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskCachingFileLoader::IsDirectory() {
|
||||
return backend_->IsDirectory();
|
||||
}
|
||||
|
||||
s64 DiskCachingFileLoader::FileSize() {
|
||||
Prepare();
|
||||
return filesize_;
|
||||
}
|
||||
|
||||
std::string DiskCachingFileLoader::Path() const {
|
||||
return backend_->Path();
|
||||
}
|
||||
|
||||
size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) {
|
||||
Prepare();
|
||||
size_t readSize;
|
||||
@@ -115,14 +105,6 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data,
|
||||
return readSize;
|
||||
}
|
||||
|
||||
bool DiskCachingFileLoader::IsRemote() {
|
||||
return backend_->IsRemote();
|
||||
}
|
||||
|
||||
void DiskCachingFileLoader::Cancel() {
|
||||
backend_->Cancel();
|
||||
}
|
||||
|
||||
std::vector<std::string> DiskCachingFileLoader::GetCachedPathsInUse() {
|
||||
std::lock_guard<std::mutex> guard(cachesMutex_);
|
||||
|
||||
@@ -139,7 +121,7 @@ std::vector<std::string> DiskCachingFileLoader::GetCachedPathsInUse() {
|
||||
void DiskCachingFileLoader::InitCache() {
|
||||
std::lock_guard<std::mutex> guard(cachesMutex_);
|
||||
|
||||
std::string path = backend_->Path();
|
||||
std::string path = ProxiedFileLoader::Path();
|
||||
auto &entry = caches_[path];
|
||||
if (!entry) {
|
||||
entry = new DiskCachingFileLoaderCache(path, filesize_);
|
||||
@@ -155,7 +137,7 @@ void DiskCachingFileLoader::ShutdownCache() {
|
||||
if (cache_->Release()) {
|
||||
// If it ran out of counts, delete it.
|
||||
delete cache_;
|
||||
caches_.erase(backend_->Path());
|
||||
caches_.erase(ProxiedFileLoader::Path());
|
||||
}
|
||||
cache_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -27,25 +27,20 @@
|
||||
|
||||
class DiskCachingFileLoaderCache;
|
||||
|
||||
class DiskCachingFileLoader : public FileLoader {
|
||||
class DiskCachingFileLoader : public ProxiedFileLoader {
|
||||
public:
|
||||
DiskCachingFileLoader(FileLoader *backend);
|
||||
~DiskCachingFileLoader() override;
|
||||
|
||||
bool IsRemote() override;
|
||||
bool Exists() override;
|
||||
bool ExistsFast() override;
|
||||
bool IsDirectory() override;
|
||||
s64 FileSize() override;
|
||||
std::string Path() const override;
|
||||
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
|
||||
return ReadAt(absolutePos, bytes * count, data, flags) / bytes;
|
||||
}
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||
|
||||
void Cancel() override;
|
||||
|
||||
static std::vector<std::string> GetCachedPathsInUse();
|
||||
|
||||
private:
|
||||
@@ -55,7 +50,6 @@ private:
|
||||
|
||||
std::once_flag preparedFlag_;
|
||||
s64 filesize_ = 0;
|
||||
FileLoader *backend_;
|
||||
DiskCachingFileLoaderCache *cache_ = nullptr;
|
||||
|
||||
// We don't support concurrent disk cache access (we use memory cached indexes.)
|
||||
|
||||
@@ -28,17 +28,23 @@ HTTPFileLoader::HTTPFileLoader(const std::string &filename)
|
||||
void HTTPFileLoader::Prepare() {
|
||||
std::call_once(preparedFlag_, [this](){
|
||||
if (!client_.Resolve(url_.Host().c_str(), url_.Port())) {
|
||||
// TODO: Should probably set some flag?
|
||||
ERROR_LOG(LOADER, "HTTP request failed, unable to resolve: %s port %d", url_.Host().c_str(), url_.Port());
|
||||
latestError_ = "Could not connect (name not resolved)";
|
||||
return;
|
||||
}
|
||||
|
||||
client_.SetDataTimeout(20.0);
|
||||
Connect();
|
||||
if (!connected_) {
|
||||
ERROR_LOG(LOADER, "HTTP request failed, failed to connect: %s port %d", url_.Host().c_str(), url_.Port());
|
||||
latestError_ = "Could not connect (refused to connect)";
|
||||
return;
|
||||
}
|
||||
|
||||
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
|
||||
if (err < 0) {
|
||||
ERROR_LOG(LOADER, "HTTP request failed, failed to send request: %s port %d", url_.Host().c_str(), url_.Port());
|
||||
latestError_ = "Could not connect (could not request data)";
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
@@ -49,6 +55,7 @@ void HTTPFileLoader::Prepare() {
|
||||
if (code != 200) {
|
||||
// Leave size at 0, invalid.
|
||||
ERROR_LOG(LOADER, "HTTP request failed, got %03d for %s", code, filename_.c_str());
|
||||
latestError_ = "Could not connect (invalid response)";
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
@@ -138,6 +145,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
|
||||
|
||||
int err = client_.SendRequest("GET", url_.Resource().c_str(), requestHeaders, nullptr);
|
||||
if (err < 0) {
|
||||
latestError_ = "Invalid response reading data";
|
||||
Disconnect();
|
||||
return 0;
|
||||
}
|
||||
@@ -147,6 +155,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
|
||||
int code = client_.ReadResponseHeaders(&readbuf, responseHeaders);
|
||||
if (code != 206) {
|
||||
ERROR_LOG(LOADER, "HTTP server did not respond with range, received code=%03d", code);
|
||||
latestError_ = "Invalid response reading data";
|
||||
Disconnect();
|
||||
return 0;
|
||||
}
|
||||
@@ -185,6 +194,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
|
||||
|
||||
if (!supportedResponse) {
|
||||
ERROR_LOG(LOADER, "HTTP server did not respond with the range we wanted.");
|
||||
latestError_ = "Invalid response reading data";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ public:
|
||||
cancelConnect_ = true;
|
||||
}
|
||||
|
||||
std::string LatestError() const override {
|
||||
return latestError_;
|
||||
}
|
||||
|
||||
private:
|
||||
void Prepare();
|
||||
|
||||
@@ -67,6 +71,7 @@ private:
|
||||
std::string filename_;
|
||||
bool connected_ = false;
|
||||
bool cancelConnect_ = false;
|
||||
const char *latestError_ = "";
|
||||
|
||||
std::once_flag preparedFlag_;
|
||||
std::mutex readAtMutex_;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
// Takes ownership of backend.
|
||||
RamCachingFileLoader::RamCachingFileLoader(FileLoader *backend)
|
||||
: backend_(backend) {
|
||||
: ProxiedFileLoader(backend) {
|
||||
filesize_ = backend->FileSize();
|
||||
if (filesize_ > 0) {
|
||||
InitCache();
|
||||
@@ -39,27 +39,25 @@ RamCachingFileLoader::~RamCachingFileLoader() {
|
||||
if (filesize_ > 0) {
|
||||
ShutdownCache();
|
||||
}
|
||||
// Takes ownership.
|
||||
delete backend_;
|
||||
}
|
||||
|
||||
bool RamCachingFileLoader::Exists() {
|
||||
if (exists_ == -1) {
|
||||
exists_ = backend_->Exists() ? 1 : 0;
|
||||
exists_ = ProxiedFileLoader::Exists() ? 1 : 0;
|
||||
}
|
||||
return exists_ == 1;
|
||||
}
|
||||
|
||||
bool RamCachingFileLoader::ExistsFast() {
|
||||
if (exists_ == -1) {
|
||||
return backend_->ExistsFast();
|
||||
return ProxiedFileLoader::ExistsFast();
|
||||
}
|
||||
return exists_ == 1;
|
||||
}
|
||||
|
||||
bool RamCachingFileLoader::IsDirectory() {
|
||||
if (isDirectory_ == -1) {
|
||||
isDirectory_ = backend_->IsDirectory() ? 1 : 0;
|
||||
isDirectory_ = ProxiedFileLoader::IsDirectory() ? 1 : 0;
|
||||
}
|
||||
return isDirectory_ == 1;
|
||||
}
|
||||
@@ -68,10 +66,6 @@ s64 RamCachingFileLoader::FileSize() {
|
||||
return filesize_;
|
||||
}
|
||||
|
||||
std::string RamCachingFileLoader::Path() const {
|
||||
return backend_->Path();
|
||||
}
|
||||
|
||||
size_t RamCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) {
|
||||
size_t readSize = 0;
|
||||
if (cache_ == nullptr || (flags & Flags::HINT_UNCACHED) != 0) {
|
||||
@@ -129,7 +123,7 @@ void RamCachingFileLoader::Cancel() {
|
||||
aheadCancel_ = true;
|
||||
}
|
||||
|
||||
backend_->Cancel();
|
||||
ProxiedFileLoader::Cancel();
|
||||
}
|
||||
|
||||
size_t RamCachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) {
|
||||
@@ -270,7 +264,3 @@ u32 RamCachingFileLoader::NextAheadBlock() {
|
||||
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
bool RamCachingFileLoader::IsRemote() {
|
||||
return backend_->IsRemote();
|
||||
}
|
||||
@@ -23,17 +23,15 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/Loaders.h"
|
||||
|
||||
class RamCachingFileLoader : public FileLoader {
|
||||
class RamCachingFileLoader : public ProxiedFileLoader {
|
||||
public:
|
||||
RamCachingFileLoader(FileLoader *backend);
|
||||
~RamCachingFileLoader() override;
|
||||
|
||||
bool IsRemote() override;
|
||||
bool Exists() override;
|
||||
bool ExistsFast() override;
|
||||
bool IsDirectory() override;
|
||||
s64 FileSize() override;
|
||||
std::string Path() const override;
|
||||
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
|
||||
return ReadAt(absolutePos, bytes * count, data, flags) / bytes;
|
||||
@@ -59,7 +57,6 @@ private:
|
||||
};
|
||||
|
||||
s64 filesize_ = 0;
|
||||
FileLoader *backend_;
|
||||
u8 *cache_ = nullptr;
|
||||
int exists_ = -1;
|
||||
int isDirectory_ = -1;
|
||||
|
||||
@@ -19,47 +19,38 @@
|
||||
|
||||
// Takes ownership of backend.
|
||||
RetryingFileLoader::RetryingFileLoader(FileLoader *backend)
|
||||
: backend_(backend) {
|
||||
}
|
||||
|
||||
RetryingFileLoader::~RetryingFileLoader() {
|
||||
// Takes ownership.
|
||||
delete backend_;
|
||||
: ProxiedFileLoader(backend) {
|
||||
}
|
||||
|
||||
bool RetryingFileLoader::Exists() {
|
||||
if (!backend_->Exists()) {
|
||||
if (!ProxiedFileLoader::Exists()) {
|
||||
// Retry once, immediately.
|
||||
return backend_->Exists();
|
||||
return ProxiedFileLoader::Exists();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RetryingFileLoader::ExistsFast() {
|
||||
if (!backend_->ExistsFast()) {
|
||||
if (!ProxiedFileLoader::ExistsFast()) {
|
||||
// Retry once, immediately.
|
||||
return backend_->ExistsFast();
|
||||
return ProxiedFileLoader::ExistsFast();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RetryingFileLoader::IsDirectory() {
|
||||
// Can't tell if it's an error either way.
|
||||
return backend_->IsDirectory();
|
||||
return ProxiedFileLoader::IsDirectory();
|
||||
}
|
||||
|
||||
s64 RetryingFileLoader::FileSize() {
|
||||
s64 filesize = backend_->FileSize();
|
||||
s64 filesize = ProxiedFileLoader::FileSize();
|
||||
if (filesize == 0) {
|
||||
return backend_->FileSize();
|
||||
return ProxiedFileLoader::FileSize();
|
||||
}
|
||||
return filesize;
|
||||
}
|
||||
|
||||
std::string RetryingFileLoader::Path() const {
|
||||
return backend_->Path();
|
||||
}
|
||||
|
||||
size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) {
|
||||
size_t readSize = backend_->ReadAt(absolutePos, bytes, data, flags);
|
||||
|
||||
@@ -72,11 +63,3 @@ size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Fla
|
||||
|
||||
return readSize;
|
||||
}
|
||||
|
||||
bool RetryingFileLoader::IsRemote() {
|
||||
return backend_->IsRemote();
|
||||
}
|
||||
|
||||
void RetryingFileLoader::Cancel() {
|
||||
backend_->Cancel();
|
||||
}
|
||||
@@ -20,29 +20,22 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/Loaders.h"
|
||||
|
||||
class RetryingFileLoader : public FileLoader {
|
||||
class RetryingFileLoader : public ProxiedFileLoader {
|
||||
public:
|
||||
RetryingFileLoader(FileLoader *backend);
|
||||
~RetryingFileLoader() override;
|
||||
|
||||
bool IsRemote() override;
|
||||
bool Exists() override;
|
||||
bool ExistsFast() override;
|
||||
bool IsDirectory() override;
|
||||
s64 FileSize() override;
|
||||
std::string Path() const override;
|
||||
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
|
||||
return ReadAt(absolutePos, bytes * count, data, flags) / bytes;
|
||||
}
|
||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||
|
||||
void Cancel() override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
MAX_RETRIES = 3,
|
||||
};
|
||||
|
||||
FileLoader *backend_;
|
||||
};
|
||||
@@ -66,9 +66,6 @@ static bool FixFilenameCase(const std::string &path, std::string &filename)
|
||||
}
|
||||
|
||||
//TODO: lookup filename in cache for "path"
|
||||
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; } diren;
|
||||
struct dirent_large;
|
||||
struct dirent *result = NULL;
|
||||
|
||||
DIR *dirp = opendir(path.c_str());
|
||||
@@ -77,7 +74,7 @@ static bool FixFilenameCase(const std::string &path, std::string &filename)
|
||||
|
||||
bool retValue = false;
|
||||
|
||||
while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
|
||||
while ((result = readdir(dirp)))
|
||||
{
|
||||
if (strlen(result->d_name) != filenameSize)
|
||||
continue;
|
||||
@@ -281,8 +278,10 @@ bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, Fil
|
||||
|
||||
#if HOST_IS_CASE_SENSITIVE
|
||||
if (!success && !(access & FILEACCESS_CREATE)) {
|
||||
if (!FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) )
|
||||
return 0; // or go on and attempt (for a better error code than just 0?)
|
||||
if (!FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST)) {
|
||||
error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
fullName = GetLocalPath(basePath,fileName);
|
||||
const char *fullNameC = fullName.c_str();
|
||||
|
||||
|
||||
@@ -661,7 +661,7 @@ static int Hook_hexyzforce_monoclome_thread() {
|
||||
|
||||
static int Hook_starocean_write_stencil() {
|
||||
const u32 fb_address = currentMIPS->r[MIPS_REG_T7];
|
||||
if (Memory::IsVRAMAddress(fb_address) && !g_Config.bDisableStencilTest) {
|
||||
if (Memory::IsVRAMAddress(fb_address)) {
|
||||
gpu->PerformStencilUpload(fb_address, 0x00088000);
|
||||
}
|
||||
return 0;
|
||||
|
||||
+20
-6
@@ -503,6 +503,18 @@ static void DoFrameDropLogging(float scaledTimestep) {
|
||||
}
|
||||
}
|
||||
|
||||
static int CalculateFrameSkip() {
|
||||
int frameSkipNum;
|
||||
if (g_Config.iFrameSkipType == 1) {
|
||||
// Calculate the frames to skip dynamically using the set percentage of the current fps
|
||||
frameSkipNum = ceil( flips * (static_cast<double>(g_Config.iFrameSkip) / 100.00) );
|
||||
} else {
|
||||
// Use the set number of frames to skip
|
||||
frameSkipNum = g_Config.iFrameSkip;
|
||||
}
|
||||
return frameSkipNum;
|
||||
}
|
||||
|
||||
// Let's collect all the throttling and frameskipping logic here.
|
||||
static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
|
||||
PROFILE_THIS_SCOPE("timing");
|
||||
@@ -553,15 +565,16 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
|
||||
// Auto-frameskip automatically if speed limit is set differently than the default.
|
||||
bool useAutoFrameskip = g_Config.bAutoFrameSkip && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
bool forceFrameskip = (fpsLimiter == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 > 60) || (fpsLimiter == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 > 60);
|
||||
int frameSkipNum = CalculateFrameSkip();
|
||||
if (g_Config.bAutoFrameSkip || forceFrameskip) {
|
||||
// autoframeskip
|
||||
// Argh, we are falling behind! Let's skip a frame and see if we catch up.
|
||||
if (curFrameTime > nextFrameTime && doFrameSkip) {
|
||||
skipFrame = true;
|
||||
}
|
||||
} else if (g_Config.iFrameSkip >= 1) {
|
||||
} else if (frameSkipNum >= 1) {
|
||||
// fixed frameskip
|
||||
if (numSkippedFrames >= g_Config.iFrameSkip)
|
||||
if (numSkippedFrames >= frameSkipNum)
|
||||
skipFrame = false;
|
||||
else
|
||||
skipFrame = true;
|
||||
@@ -734,9 +747,10 @@ void __DisplayFlip(int cyclesLate) {
|
||||
DoFrameTiming(throttle, skipFrame, (float)numVBlanksSinceFlip * timePerVblank);
|
||||
|
||||
int maxFrameskip = 8;
|
||||
int frameSkipNum = CalculateFrameSkip();
|
||||
if (throttle) {
|
||||
// 4 here means 1 drawn, 4 skipped - so 12 fps minimum.
|
||||
maxFrameskip = g_Config.iFrameSkip;
|
||||
maxFrameskip = frameSkipNum;
|
||||
}
|
||||
if (numSkippedFrames >= maxFrameskip || GPURecord::IsActivePending()) {
|
||||
skipFrame = false;
|
||||
@@ -914,7 +928,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync)
|
||||
|
||||
s64 delayCycles = 0;
|
||||
// Don't count transitions between display off and display on.
|
||||
if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && g_Config.iForceMaxEmulatedFPS > 0) {
|
||||
if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && PSP_CoreParameter().compat.flags().ForceMax60FPS) {
|
||||
// sceDisplaySetFramebuf() isn't supposed to delay threads at all. This is a hack.
|
||||
// So let's only delay when it's more than 1ms.
|
||||
const s64 FLIP_DELAY_CYCLES_MIN = usToCycles(1000);
|
||||
@@ -928,7 +942,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync)
|
||||
u64 now = CoreTiming::GetTicks();
|
||||
s64 cyclesAhead = nextFlipCycles - now;
|
||||
if (cyclesAhead > FLIP_DELAY_CYCLES_MIN) {
|
||||
if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS && gpuStats.numClears > 0) {
|
||||
if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS) {
|
||||
delayCycles = cyclesAhead;
|
||||
} else {
|
||||
++lastFlipsTooFrequent;
|
||||
@@ -938,7 +952,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync)
|
||||
}
|
||||
|
||||
// 1001 to account for NTSC timing (59.94 fps.)
|
||||
u64 expected = msToCycles(g_Config.bRefreshAt60Hz ? 1000 : 1001) / g_Config.iForceMaxEmulatedFPS - LEEWAY_CYCLES_PER_FLIP;
|
||||
u64 expected = msToCycles(g_Config.bRefreshAt60Hz ? 1000 : 1001) / 60 - LEEWAY_CYCLES_PER_FLIP;
|
||||
lastFlipCycles = now;
|
||||
nextFlipCycles = std::max(lastFlipCycles, nextFlipCycles) + expected;
|
||||
}
|
||||
|
||||
+21
-10
@@ -253,6 +253,14 @@ public:
|
||||
|
||||
u64 __IoCompleteAsyncIO(FileNode *f);
|
||||
|
||||
static int GetIOTimingMethod() {
|
||||
if (PSP_CoreParameter().compat.flags().ForceUMDDelay) {
|
||||
return IOTIMING_REALISTIC;
|
||||
} else {
|
||||
return g_Config.iIOTimingMethod;
|
||||
}
|
||||
}
|
||||
|
||||
static void TellFsThreadEnded (SceUID threadID) {
|
||||
pspFileSystem.ThreadEnded(threadID);
|
||||
}
|
||||
@@ -339,7 +347,8 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_Config.iIOTimingMethod == IOTIMING_HOST) {
|
||||
int ioTimingMethod = GetIOTimingMethod();
|
||||
if (ioTimingMethod == IOTIMING_HOST) {
|
||||
// Not all async operations actually queue up. Maybe should separate them?
|
||||
if (!ioManager.HasResult(f->handle) && ioManager.HasOperation(f->handle)) {
|
||||
// Try again in another 0.5ms until the IO completes on the host.
|
||||
@@ -347,7 +356,7 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) {
|
||||
return;
|
||||
}
|
||||
__IoCompleteAsyncIO(f);
|
||||
} else if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) {
|
||||
} else if (ioTimingMethod == IOTIMING_REALISTIC) {
|
||||
u64 finishTicks = __IoCompleteAsyncIO(f);
|
||||
if (finishTicks > CoreTiming::GetTicks()) {
|
||||
// Reschedule for later, since we now know how long it ought to take.
|
||||
@@ -396,13 +405,14 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_Config.iIOTimingMethod == IOTIMING_HOST) {
|
||||
int ioTimingMethod = GetIOTimingMethod();
|
||||
if (ioTimingMethod == IOTIMING_HOST) {
|
||||
if (!ioManager.HasResult(f->handle)) {
|
||||
// Try again in another 0.5ms until the IO completes on the host.
|
||||
CoreTiming::ScheduleEvent(usToCycles(500) - cyclesLate, syncNotifyEvent, userdata);
|
||||
return;
|
||||
}
|
||||
} else if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) {
|
||||
} else if (ioTimingMethod == IOTIMING_REALISTIC) {
|
||||
u64 finishTicks = ioManager.ResultFinishTicks(f->handle);
|
||||
if (finishTicks > CoreTiming::GetTicks()) {
|
||||
// Reschedule for later when the result should finish.
|
||||
@@ -723,7 +733,8 @@ static u32 sceKernelStderr() {
|
||||
u64 __IoCompleteAsyncIO(FileNode *f) {
|
||||
PROFILE_THIS_SCOPE("io_rw");
|
||||
|
||||
if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) {
|
||||
int ioTimingMethod = GetIOTimingMethod();
|
||||
if (ioTimingMethod == IOTIMING_REALISTIC) {
|
||||
u64 finishTicks = ioManager.ResultFinishTicks(f->handle);
|
||||
if (finishTicks > CoreTiming::GetTicks()) {
|
||||
return finishTicks;
|
||||
@@ -921,7 +932,7 @@ static bool __IoRead(int &result, int id, u32 data_addr, int size, int &us) {
|
||||
ioManager.ScheduleOperation(ev);
|
||||
return false;
|
||||
} else {
|
||||
if (g_Config.iIOTimingMethod != IOTIMING_REALISTIC) {
|
||||
if (GetIOTimingMethod() != IOTIMING_REALISTIC) {
|
||||
result = (int) pspFileSystem.ReadFile(f->handle, data, size);
|
||||
} else {
|
||||
result = (int) pspFileSystem.ReadFile(f->handle, data, size, us);
|
||||
@@ -991,7 +1002,7 @@ static u32 sceIoReadAsync(int id, u32 data_addr, int size) {
|
||||
int us;
|
||||
bool complete = __IoRead(result, id, data_addr, size, us);
|
||||
if (complete) {
|
||||
f->asyncResult = result;
|
||||
f->asyncResult = (s64)result;
|
||||
DEBUG_LOG(SCEIO, "%llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
|
||||
} else {
|
||||
DEBUG_LOG(SCEIO, "sceIoReadAsync(%d, %08x, %x): deferring result", id, data_addr, size);
|
||||
@@ -1056,7 +1067,7 @@ static bool __IoWrite(int &result, int id, u32 data_addr, int size, int &us) {
|
||||
ioManager.ScheduleOperation(ev);
|
||||
return false;
|
||||
} else {
|
||||
if (g_Config.iIOTimingMethod != IOTIMING_REALISTIC) {
|
||||
if (GetIOTimingMethod() != IOTIMING_REALISTIC) {
|
||||
result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size);
|
||||
} else {
|
||||
result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size, us);
|
||||
@@ -1125,7 +1136,7 @@ static u32 sceIoWriteAsync(int id, u32 data_addr, int size) {
|
||||
int us;
|
||||
bool complete = __IoWrite(result, id, data_addr, size, us);
|
||||
if (complete) {
|
||||
f->asyncResult = result;
|
||||
f->asyncResult = (s64)result;
|
||||
DEBUG_LOG(SCEIO, "%llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
|
||||
} else {
|
||||
DEBUG_LOG(SCEIO, "sceIoWriteAsync(%d, %08x, %x): deferring result", id, data_addr, size);
|
||||
@@ -1935,7 +1946,7 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode)
|
||||
f = new FileNode();
|
||||
f->handle = kernelObjects.Create(f);
|
||||
f->fullpath = filename;
|
||||
f->asyncResult = error == 0 ? SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND : error;
|
||||
f->asyncResult = error == 0 ? (s64)SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND : (s64)error;
|
||||
f->closePending = true;
|
||||
|
||||
fd = __IoAllocFd(f);
|
||||
|
||||
@@ -684,7 +684,9 @@ const HLEFunction Kernel_Library[] =
|
||||
|
||||
static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) {
|
||||
ERROR_LOG(SCEKERNEL, "Untested sysclib_memcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
|
||||
memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size);
|
||||
if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) {
|
||||
memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,13 +84,14 @@ enum {
|
||||
};
|
||||
|
||||
// This is a workaround for misbehaving homebrew (like TBL's Suicide Barbie (Final)).
|
||||
static const char *lieAboutSuccessModules[] = {
|
||||
static const char * const lieAboutSuccessModules[] = {
|
||||
"flash0:/kd/audiocodec.prx",
|
||||
"flash0:/kd/audiocodec_260.prx",
|
||||
"flash0:/kd/libatrac3plus.prx",
|
||||
"disc0:/PSP_GAME/SYSDIR/UPDATE/EBOOT.BIN",
|
||||
};
|
||||
|
||||
static const char *blacklistedModules[] = {
|
||||
static const char * const blacklistedModules[] = {
|
||||
"sceATRAC3plus_Library",
|
||||
"sceFont_Library",
|
||||
"SceFont_Library",
|
||||
|
||||
@@ -1599,7 +1599,6 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
Memory::Write_U32(1, attrAddr);
|
||||
}
|
||||
|
||||
|
||||
DEBUG_LOG(ME, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr);
|
||||
// TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something.
|
||||
// There's definitely more to it, but ultimately it seems games should expect it to delay randomly.
|
||||
@@ -1664,6 +1663,7 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
// Instead, let's abuse it to keep track of the stream number.
|
||||
if (streamInfo != ctx->streamMap.end()) {
|
||||
atracAu.esBuffer = streamInfo->second.num;
|
||||
ctx->mediaengine->setAudioStream(streamInfo->second.num);
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ static const int PSMF_AUDIO_STREAM_ID = 0xBD;
|
||||
struct SceMpegAu {
|
||||
s64_le pts; // presentation time stamp
|
||||
s64_le dts; // decode time stamp
|
||||
u32_le esBuffer;
|
||||
u32_le esBuffer; // WARNING: We abuse this to keep track of the stream number!
|
||||
u32_le esSize;
|
||||
|
||||
void read(u32 addr);
|
||||
|
||||
@@ -22,8 +22,7 @@ void Register_sceUsbGps();
|
||||
void __UsbGpsInit();
|
||||
void __UsbGpsDoState(PointerWrap &p);
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
short year;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
@@ -185,8 +186,14 @@ static int sceUtilitySavedataInitStart(u32 paramAddr)
|
||||
{
|
||||
if (currentDialogActive && currentDialogType != UTILITY_DIALOG_SAVEDATA)
|
||||
{
|
||||
WARN_LOG(SCEUTILITY, "sceUtilitySavedataInitStart(%08x): wrong dialog type", paramAddr);
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
if (PSP_CoreParameter().compat.flags().YugiohSaveFix)
|
||||
{
|
||||
WARN_LOG(SCEUTILITY, "Yugioh Savedata Correction");
|
||||
}
|
||||
else {
|
||||
WARN_LOG(SCEUTILITY, "sceUtilitySavedataInitStart(%08x): wrong dialog type", paramAddr);
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
oldStatus = 100;
|
||||
|
||||
+3
-1
@@ -294,7 +294,9 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) {
|
||||
|
||||
case IdentifiedFileType::ERROR_IDENTIFYING:
|
||||
ERROR_LOG(LOADER, "Could not read file");
|
||||
*error_string = "Error reading file";
|
||||
*error_string = fileLoader ? fileLoader->LatestError() : "";
|
||||
if (error_string->empty())
|
||||
*error_string = "Error reading file";
|
||||
break;
|
||||
|
||||
case IdentifiedFileType::ARCHIVE_RAR:
|
||||
|
||||
@@ -93,6 +93,48 @@ public:
|
||||
// Cancel any operations that might block, if possible.
|
||||
virtual void Cancel() {
|
||||
}
|
||||
|
||||
virtual std::string LatestError() const {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
class ProxiedFileLoader : public FileLoader {
|
||||
public:
|
||||
ProxiedFileLoader(FileLoader *backend) : backend_(backend) {
|
||||
}
|
||||
~ProxiedFileLoader() override {
|
||||
// Takes ownership.
|
||||
delete backend_;
|
||||
}
|
||||
|
||||
bool IsRemote() override {
|
||||
return backend_->IsRemote();
|
||||
}
|
||||
bool Exists() override {
|
||||
return backend_->Exists();
|
||||
}
|
||||
bool ExistsFast() override {
|
||||
return backend_->ExistsFast();
|
||||
}
|
||||
bool IsDirectory() override {
|
||||
return backend_->IsDirectory();
|
||||
}
|
||||
s64 FileSize() override {
|
||||
return backend_->FileSize();
|
||||
}
|
||||
std::string Path() const override {
|
||||
return backend_->Path();
|
||||
}
|
||||
void Cancel() override {
|
||||
backend_->Cancel();
|
||||
}
|
||||
std::string LatestError() const override {
|
||||
return backend_->LatestError();
|
||||
}
|
||||
|
||||
protected:
|
||||
FileLoader *backend_;
|
||||
};
|
||||
|
||||
inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) {
|
||||
|
||||
@@ -43,7 +43,7 @@ using namespace MIPSAnalyst;
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp
|
||||
@@ -72,7 +72,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_IType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_IMM);
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
|
||||
u32 uimm = op & 0xFFFF;
|
||||
u32 suimm = (u32)(s32)simm;
|
||||
@@ -150,7 +150,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_RType2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_RType3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
@@ -502,7 +502,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_ShiftType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
int fd = _FD;
|
||||
@@ -529,7 +529,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Special3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
@@ -591,7 +591,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Allegrex(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
@@ -645,7 +645,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Allegrex2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
@@ -677,7 +677,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_MulDivType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(MULDIV);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp
|
||||
@@ -54,7 +54,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_FPU3op(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
|
||||
int ft = _FT;
|
||||
int fs = _FS;
|
||||
@@ -92,7 +92,7 @@ extern int logBlocks;
|
||||
|
||||
void ArmJit::Comp_FPULS(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_FPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
s32 offset = (s16)(op & 0xFFFF);
|
||||
@@ -193,7 +193,7 @@ void ArmJit::Comp_FPULS(MIPSOpcode op)
|
||||
}
|
||||
|
||||
void ArmJit::Comp_FPUComp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_COMP);
|
||||
|
||||
int opc = op & 0xF;
|
||||
if (opc >= 8) opc -= 8; // alias
|
||||
@@ -258,7 +258,7 @@ void ArmJit::Comp_FPUComp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::Comp_FPU2op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
|
||||
int fs = _FS;
|
||||
int fd = _FD;
|
||||
@@ -350,7 +350,7 @@ void ArmJit::Comp_FPU2op(MIPSOpcode op) {
|
||||
|
||||
void ArmJit::Comp_mxc1(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_XFER);
|
||||
|
||||
int fs = _FS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp
|
||||
@@ -111,14 +111,14 @@ namespace MIPSComp
|
||||
}
|
||||
|
||||
void ArmJit::Comp_ITypeMemLR(MIPSOpcode op, bool load) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
CheckMemoryBreakpoint();
|
||||
int offset = (signed short)(op & 0xFFFF);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
int o = op >> 26;
|
||||
|
||||
if (!js.inDelaySlot) {
|
||||
if (!js.inDelaySlot && !jo.Disabled(JitDisable::LSU_UNALIGNED)) {
|
||||
// Optimisation: Combine to single unaligned load/store
|
||||
bool isLeft = (o == 34 || o == 42);
|
||||
CheckMemoryBreakpoint(1);
|
||||
@@ -260,7 +260,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_ITypeMem(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
CheckMemoryBreakpoint();
|
||||
int offset = (signed short)(op&0xFFFF);
|
||||
bool load = false;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
|
||||
#define NEON_IF_AVAILABLE(func) { if (jo.useNEONVFPU) { func(op); return; } }
|
||||
@@ -87,7 +87,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_VPFX(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int data = op & 0xFFFFF;
|
||||
int regnum = (op >> 24) & 3;
|
||||
switch (regnum) {
|
||||
@@ -225,7 +225,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_SV(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_SV);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
s32 offset = (signed short)(op & 0xFFFC);
|
||||
@@ -332,7 +332,7 @@ namespace MIPSComp
|
||||
void ArmJit::Comp_SVQ(MIPSOpcode op)
|
||||
{
|
||||
NEON_IF_AVAILABLE(CompNEON_SVQ);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
int imm = (signed short)(op&0xFFFC);
|
||||
@@ -478,7 +478,7 @@ namespace MIPSComp
|
||||
void ArmJit::Comp_VVectorInit(MIPSOpcode op)
|
||||
{
|
||||
NEON_IF_AVAILABLE(CompNEON_VVectorInit);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
// WARNING: No prefix support!
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
@@ -515,7 +515,7 @@ namespace MIPSComp
|
||||
void ArmJit::Comp_VIdt(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VIdt);
|
||||
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -553,7 +553,7 @@ namespace MIPSComp
|
||||
void ArmJit::Comp_VMatrixInit(MIPSOpcode op)
|
||||
{
|
||||
NEON_IF_AVAILABLE(CompNEON_VMatrixInit);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
// Don't think matrix init ops care about prefixes.
|
||||
// DISABLE;
|
||||
@@ -601,7 +601,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_VHdp(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VHdp);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -644,7 +644,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vhoriz(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vhoriz);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -687,7 +687,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_VDot(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VDot);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -724,7 +724,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_VecDo3(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VecDo3);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -884,7 +884,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_VV2Op(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VV2Op);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1077,7 +1077,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vi2f(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vi2f);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1124,7 +1124,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vh2f(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vh2f);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1186,7 +1186,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vf2i(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vf2i);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
@@ -1256,7 +1256,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Mftv(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Mftv);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int imm = op & 0xFF;
|
||||
MIPSGPReg rt = _RT;
|
||||
@@ -1331,7 +1331,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vmfvc(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vmtvc);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
@@ -1350,7 +1350,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vmtvc(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vmtvc);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
@@ -1377,7 +1377,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vmmov(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vmmov);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// This probably ignores prefixes for all sane intents and purposes.
|
||||
if (_VS == _VD) {
|
||||
@@ -1415,7 +1415,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_VScl(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VScl);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1464,7 +1464,7 @@ namespace MIPSComp
|
||||
}
|
||||
|
||||
void ArmJit::Comp_Vmmul(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1513,7 +1513,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vtfm(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vtfm);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1584,7 +1584,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vi2x(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vi2x);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1662,7 +1662,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vx2i(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vx2i);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1751,7 +1751,7 @@ namespace MIPSComp
|
||||
void ArmJit::Comp_VCrossQuat(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VCrossQuat);
|
||||
// This op does not support prefixes anyway.
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1831,7 +1831,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vcmp(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vcmp);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -2019,7 +2019,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vcmov(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vcmov);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -2070,7 +2070,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Viim(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Viim);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -2088,7 +2088,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vfim(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vfim);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -2108,7 +2108,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vcst(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vcst);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -2178,7 +2178,7 @@ namespace MIPSComp
|
||||
void ArmJit::Comp_VRot(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_VRot);
|
||||
// VRot probably doesn't accept prefixes anyway.
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -2244,7 +2244,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vsgn(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vsgn);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -2293,7 +2293,7 @@ namespace MIPSComp
|
||||
|
||||
void ArmJit::Comp_Vocp(MIPSOpcode op) {
|
||||
NEON_IF_AVAILABLE(CompNEON_Vocp);
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
#define DISABLE_UNKNOWN_PREFIX { WLOG("DISABLE: Unknown Prefix in %s", __FUNCTION__); fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
|
||||
@@ -82,7 +82,7 @@ static const float zero = 0.0f;
|
||||
|
||||
|
||||
void ArmJit::CompNEON_VecDo3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -158,7 +158,7 @@ void ArmJit::CompNEON_VecDo3(MIPSOpcode op) {
|
||||
// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
|
||||
void ArmJit::CompNEON_SV(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
// Remember to use single lane stores here and not VLDR/VSTR - switching usage
|
||||
@@ -276,7 +276,7 @@ inline int MIPS_GET_VQVT(u32 op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_SVQ(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
int offset = (signed short)(op & 0xFFFC);
|
||||
@@ -425,7 +425,7 @@ void ArmJit::CompNEON_SVQ(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VVectorInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
// WARNING: No prefix support!
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
@@ -450,7 +450,7 @@ void ArmJit::CompNEON_VVectorInit(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VDot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -484,7 +484,7 @@ void ArmJit::CompNEON_VDot(MIPSOpcode op) {
|
||||
|
||||
|
||||
void ArmJit::CompNEON_VHdp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -496,7 +496,7 @@ void ArmJit::CompNEON_VHdp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VScl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -515,7 +515,7 @@ void ArmJit::CompNEON_VScl(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VV2Op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -666,7 +666,7 @@ void ArmJit::CompNEON_VV2Op(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Mftv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int imm = op & 0xFF;
|
||||
MIPSGPReg rt = _RT;
|
||||
switch ((op >> 21) & 0x1f) {
|
||||
@@ -746,7 +746,7 @@ void ArmJit::CompNEON_Vmfvc(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vmtvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
@@ -767,7 +767,7 @@ void ArmJit::CompNEON_Vmtvc(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VMatrixInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
MatrixSize msz = GetMtxSize(op);
|
||||
int n = GetMatrixSide(msz);
|
||||
@@ -828,7 +828,7 @@ void ArmJit::CompNEON_VMatrixInit(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vmmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (_VS == _VD) {
|
||||
// A lot of these no-op matrix moves in Wipeout... Just drop the instruction entirely.
|
||||
return;
|
||||
@@ -856,7 +856,7 @@ void ArmJit::CompNEON_Vmmov(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vmmul(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
MatrixSize msz = GetMtxSize(op);
|
||||
int n = GetMatrixSide(msz);
|
||||
@@ -895,7 +895,7 @@ void ArmJit::CompNEON_Vmmul(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vmscl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
MatrixSize msz = GetMtxSize(op);
|
||||
|
||||
@@ -920,7 +920,7 @@ void ArmJit::CompNEON_Vmscl(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vtfm(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -986,7 +986,7 @@ void ArmJit::CompNEON_Vf2i(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vi2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1012,6 +1012,7 @@ void ArmJit::CompNEON_Vi2f(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vh2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (!cpu_info.bHalf) {
|
||||
// No hardware support for half-to-float, fallback to interpreter
|
||||
// TODO: Translate the fast SSE solution to standard integer/VFP stuff
|
||||
@@ -1045,7 +1046,7 @@ void ArmJit::CompNEON_Vh2f(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vcst(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -1063,7 +1064,7 @@ void ArmJit::CompNEON_Vcst(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vhoriz(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -1102,7 +1103,7 @@ void ArmJit::CompNEON_Vhoriz(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VRot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
@@ -1121,7 +1122,7 @@ void ArmJit::CompNEON_VRot(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_VIdt(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -1167,7 +1168,7 @@ void ArmJit::CompNEON_VIdt(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vcmp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1298,7 +1299,7 @@ void ArmJit::CompNEON_Vcmp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vcmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1341,7 +1342,7 @@ void ArmJit::CompNEON_Vcmov(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Viim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1358,7 +1359,7 @@ void ArmJit::CompNEON_Viim(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vfim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1379,7 +1380,7 @@ void ArmJit::CompNEON_Vfim(MIPSOpcode op) {
|
||||
// https://code.google.com/p/bullet/source/browse/branches/PhysicsEffects/include/vecmath/neon/vectormath_neon_assembly_implementations.S?r=2488
|
||||
void ArmJit::CompNEON_VCrossQuat(MIPSOpcode op) {
|
||||
// This op does not support prefixes anyway.
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE_UNKNOWN_PREFIX;
|
||||
}
|
||||
@@ -1427,7 +1428,7 @@ void ArmJit::CompNEON_Vsgn(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void ArmJit::CompNEON_Vocp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
using namespace ArmJitConstants;
|
||||
|
||||
static void DisassembleArm(const u8 *data, int size) {
|
||||
void DisassembleArm(const u8 *data, int size) {
|
||||
char temp[256];
|
||||
for (int i = 0; i < size; i += 4) {
|
||||
const u32 *codePtr = (const u32 *)(data + i);
|
||||
|
||||
@@ -44,7 +44,7 @@ using namespace MIPSAnalyst;
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
@@ -70,7 +70,7 @@ void Arm64Jit::CompImmLogic(MIPSGPReg rs, MIPSGPReg rt, u32 uimm, void (ARM64XEm
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_IType(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_IMM);
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
|
||||
u32 uimm = op & 0xFFFF;
|
||||
u32 suimm = (u32)(s32)simm;
|
||||
@@ -146,7 +146,7 @@ void Arm64Jit::Comp_IType(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_RType2(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
@@ -234,7 +234,7 @@ void Arm64Jit::CompType3(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, void (ARM64XE
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_RType3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -406,7 +406,7 @@ void Arm64Jit::CompShiftVar(MIPSOpcode op, Arm64Gen::ShiftType shiftType) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_ShiftType(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
int fd = _FD;
|
||||
@@ -431,7 +431,7 @@ void Arm64Jit::Comp_ShiftType(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Special3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -479,7 +479,7 @@ void Arm64Jit::Comp_Special3(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Allegrex(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
@@ -529,7 +529,7 @@ void Arm64Jit::Comp_Allegrex(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Allegrex2(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
@@ -560,7 +560,7 @@ void Arm64Jit::Comp_Allegrex2(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_MulDivType(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(MULDIV);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
@@ -60,7 +60,7 @@ namespace MIPSComp {
|
||||
using namespace Arm64JitConstants;
|
||||
|
||||
void Arm64Jit::Comp_FPU3op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
|
||||
int ft = _FT;
|
||||
int fs = _FS;
|
||||
@@ -80,7 +80,7 @@ void Arm64Jit::Comp_FPU3op(MIPSOpcode op) {
|
||||
|
||||
void Arm64Jit::Comp_FPULS(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_FPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
// Surprisingly, these work fine alraedy.
|
||||
@@ -152,7 +152,7 @@ void Arm64Jit::Comp_FPULS(MIPSOpcode op)
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_FPUComp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_COMP);
|
||||
|
||||
int opc = op & 0xF;
|
||||
if (opc >= 8) opc -= 8; // alias
|
||||
@@ -198,7 +198,7 @@ void Arm64Jit::Comp_FPUComp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_FPU2op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
int fs = _FS;
|
||||
int fd = _FD;
|
||||
|
||||
@@ -301,7 +301,7 @@ void Arm64Jit::Comp_FPU2op(MIPSOpcode op) {
|
||||
|
||||
void Arm64Jit::Comp_mxc1(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_XFER);
|
||||
|
||||
int fs = _FS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
@@ -110,14 +110,14 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_ITypeMemLR(MIPSOpcode op, bool load) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
CheckMemoryBreakpoint();
|
||||
int offset = (signed short)(op & 0xFFFF);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
int o = op >> 26;
|
||||
|
||||
if (!js.inDelaySlot) {
|
||||
if (!js.inDelaySlot && !jo.Disabled(JitDisable::LSU_UNALIGNED)) {
|
||||
// Optimisation: Combine to single unaligned load/store
|
||||
bool isLeft = (o == 34 || o == 42);
|
||||
CheckMemoryBreakpoint(1);
|
||||
@@ -256,7 +256,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_ITypeMem(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
int offset = (signed short)(op & 0xFFFF);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
@@ -80,7 +80,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VPFX(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int data = op & 0xFFFFF;
|
||||
int regnum = (op >> 24) & 3;
|
||||
switch (regnum) {
|
||||
@@ -201,7 +201,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_SV(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
s32 offset = (signed short)(op & 0xFFFC);
|
||||
@@ -275,7 +275,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_SVQ(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
CheckMemoryBreakpoint();
|
||||
|
||||
int imm = (signed short)(op&0xFFFC);
|
||||
@@ -359,7 +359,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VVectorInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
// WARNING: No prefix support!
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
@@ -393,7 +393,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VIdt(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -428,7 +428,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VMatrixInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
// Don't think matrix init ops care about prefixes.
|
||||
// DISABLE;
|
||||
@@ -475,7 +475,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VHdp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -517,7 +517,7 @@ namespace MIPSComp {
|
||||
alignas(16) static const float vavg_table[4] = { 1.0f, 1.0f / 2.0f, 1.0f / 3.0f, 1.0f / 4.0f };
|
||||
|
||||
void Arm64Jit::Comp_Vhoriz(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -559,7 +559,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VDot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -595,7 +595,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VecDo3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -744,7 +744,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VV2Op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -884,7 +884,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vi2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -931,7 +931,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vh2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -978,6 +978,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Mftv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int imm = op & 0xFF;
|
||||
MIPSGPReg rt = _RT;
|
||||
switch ((op >> 21) & 0x1f) {
|
||||
@@ -1063,7 +1064,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vmfvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
@@ -1081,7 +1082,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vmtvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
@@ -1107,7 +1108,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vmmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// This probably ignores prefixes for all sane intents and purposes.
|
||||
if (_VS == _VD) {
|
||||
@@ -1144,7 +1145,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_VScl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1193,7 +1194,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vmmul(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1239,7 +1240,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vtfm(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1307,7 +1308,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vi2x(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1376,7 +1377,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vx2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1471,7 +1472,7 @@ namespace MIPSComp {
|
||||
|
||||
void Arm64Jit::Comp_VCrossQuat(MIPSOpcode op) {
|
||||
// This op does not support prefixes anyway.
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1550,7 +1551,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vcmp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1727,7 +1728,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vcmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1778,7 +1779,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Viim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1795,7 +1796,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vfim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1814,7 +1815,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vcst(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1882,7 +1883,7 @@ namespace MIPSComp {
|
||||
// calling the math library.
|
||||
void Arm64Jit::Comp_VRot(MIPSOpcode op) {
|
||||
// VRot probably doesn't accept prefixes anyway.
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1943,7 +1944,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void Arm64Jit::Comp_Vocp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -38,14 +38,14 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
#define INVALIDOP { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_IType(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_IMM);
|
||||
|
||||
s32 simm = (s32)_IMM16; // sign extension
|
||||
u32 uimm = (u16)_IMM16;
|
||||
@@ -87,7 +87,7 @@ void IRFrontend::Comp_IType(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_RType2(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
@@ -111,7 +111,7 @@ void IRFrontend::Comp_RType2(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_RType3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -197,7 +197,7 @@ void IRFrontend::CompShiftVar(MIPSOpcode op, IROp shiftOp) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_ShiftType(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
int sa = _SA;
|
||||
@@ -222,7 +222,7 @@ void IRFrontend::Comp_ShiftType(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Special3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -265,7 +265,7 @@ void IRFrontend::Comp_Special3(MIPSOpcode op) {
|
||||
|
||||
|
||||
void IRFrontend::Comp_Allegrex(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -293,7 +293,7 @@ void IRFrontend::Comp_Allegrex(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Allegrex2(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -315,7 +315,7 @@ void IRFrontend::Comp_Allegrex2(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_MulDivType(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(MULDIV);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -49,14 +49,14 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
#define INVALIDOP { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_FPU3op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
|
||||
int ft = _FT;
|
||||
int fs = _FS;
|
||||
@@ -74,7 +74,7 @@ void IRFrontend::Comp_FPU3op(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_FPULS(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_FPU);
|
||||
s32 offset = _IMM16;
|
||||
int ft = _FT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -97,7 +97,7 @@ void IRFrontend::Comp_FPULS(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_FPUComp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_COMP);
|
||||
|
||||
int opc = op & 0xF;
|
||||
if (opc >= 8) opc -= 8; // alias
|
||||
@@ -139,7 +139,7 @@ void IRFrontend::Comp_FPUComp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_FPU2op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
|
||||
int fs = _FS;
|
||||
int fd = _FD;
|
||||
@@ -185,7 +185,7 @@ void IRFrontend::Comp_FPU2op(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_mxc1(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_XFER);
|
||||
|
||||
int fs = _FS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
#define INVALIDOP { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
void IRFrontend::Comp_ITypeMem(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
|
||||
int offset = _IMM16;
|
||||
MIPSGPReg rt = _RT;
|
||||
@@ -106,7 +106,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Cache(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
|
||||
// int imm = (s16)(op & 0xFFFF);
|
||||
// int rs = _RS;
|
||||
|
||||
+38
-38
@@ -35,7 +35,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
#define INVALIDOP { Comp_Generic(op); return; }
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VPFX(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int data = op & 0xFFFFF;
|
||||
int regnum = (op >> 24) & 3;
|
||||
switch (regnum) {
|
||||
@@ -274,7 +274,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_SV(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
s32 offset = (signed short)(op & 0xFFFC);
|
||||
int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5);
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -296,7 +296,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_SVQ(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
int imm = (signed short)(op & 0xFFFC);
|
||||
int vt = (((op >> 16) & 0x1f)) | ((op & 1) << 5);
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -342,7 +342,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VVectorInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -368,7 +368,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VIdt(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VMatrixInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
MatrixSize sz = GetMtxSize(op);
|
||||
if (sz != M_4x4) {
|
||||
DISABLE;
|
||||
@@ -447,7 +447,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VHdp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -487,7 +487,7 @@ namespace MIPSComp {
|
||||
alignas(16) static const float vavg_table[4] = { 1.0f, 1.0f / 2.0f, 1.0f / 3.0f, 1.0f / 4.0f };
|
||||
|
||||
void IRFrontend::Comp_Vhoriz(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -524,7 +524,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VDot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -562,7 +562,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VecDo3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -721,7 +721,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VV2Op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -847,7 +847,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vi2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -894,7 +894,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vh2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
// Vector expand half to float
|
||||
// d[N*2] = float(lowerhalf(s[N])), d[N*2+1] = float(upperhalf(s[N]))
|
||||
@@ -903,7 +903,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vf2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
// Vector float to integer
|
||||
// d[N] = int(S[N] * mult)
|
||||
@@ -913,7 +913,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Mftv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int imm = op & 0xFF;
|
||||
MIPSGPReg rt = _RT;
|
||||
@@ -966,7 +966,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vmfvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
// Vector Move from vector control reg (no prefixes)
|
||||
// S[0] = VFPU_CTRL[i]
|
||||
@@ -982,7 +982,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vmtvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
// Vector Move to vector control reg (no prefixes)
|
||||
// VFPU_CTRL[i] = S[0]
|
||||
@@ -1004,7 +1004,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vmmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// Matrix move (no prefixes)
|
||||
// D[N,M] = S[N,M]
|
||||
@@ -1061,7 +1061,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vmscl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// Matrix scale, matrix by scalar (no prefixes)
|
||||
// d[N,M] = s[N,M] * t[0]
|
||||
@@ -1099,7 +1099,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VScl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1173,7 +1173,7 @@ namespace MIPSComp {
|
||||
// This may or may not be a win when using the IR interpreter...
|
||||
// Many more instructions to interpret.
|
||||
void IRFrontend::Comp_Vmmul(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// Matrix multiply (no prefixes)
|
||||
// D[0 .. N,0 .. M] = S[0 .. N, 0 .. M] * T[0 .. N,0 .. M]
|
||||
@@ -1256,7 +1256,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vtfm(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// Vertex transform, vector by matrix (no prefixes)
|
||||
// d[N] = s[N*m .. N*m + n-1] dot t[0 .. n-1]
|
||||
@@ -1358,7 +1358,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VCrs(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1372,7 +1372,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VDet(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1385,7 +1385,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vi2x(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1470,7 +1470,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vx2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1570,7 +1570,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VCrossQuat(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
// TODO: Does this instruction even look at prefixes at all?
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1627,7 +1627,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vcmp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1651,7 +1651,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vcmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1690,7 +1690,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Viim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1705,7 +1705,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vfim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1723,7 +1723,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vcst(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1747,7 +1747,7 @@ namespace MIPSComp {
|
||||
// Very heavily used by FF:CC. Should be replaced by a fast approximation instead of
|
||||
// calling the math library.
|
||||
void IRFrontend::Comp_VRot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (!js.HasNoPrefix()) {
|
||||
// Prefixes work strangely for this:
|
||||
// * They never apply to cos (whether d or s prefixes.)
|
||||
@@ -1797,7 +1797,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vsgn(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1835,7 +1835,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vocp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -1872,7 +1872,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_ColorConv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1883,7 +1883,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_Vbfy(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
|
||||
@@ -369,6 +369,7 @@ private:
|
||||
};
|
||||
|
||||
struct IROptions {
|
||||
uint32_t disableFlags;
|
||||
bool unalignedLoadStore;
|
||||
};
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ IRJit::IRJit(MIPSState *mips) : frontend_(mips->HasDefaultPrefix()), mips_(mips)
|
||||
InitIR();
|
||||
|
||||
IROptions opts{};
|
||||
opts.unalignedLoadStore = true;
|
||||
opts.disableFlags = g_Config.uJitDisableFlags;
|
||||
opts.unalignedLoadStore = opts.disableFlags & (uint32_t)JitDisable::LSU_UNALIGNED;
|
||||
frontend_.SetOptions(opts);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,35 +16,38 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/MIPS/JitCommon/JitState.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
|
||||
namespace MIPSComp {
|
||||
JitOptions::JitOptions() {
|
||||
disableFlags = g_Config.uJitDisableFlags;
|
||||
|
||||
// x86
|
||||
enableVFPUSIMD = true;
|
||||
enableVFPUSIMD = !Disabled(JitDisable::SIMD);
|
||||
// Set by Asm if needed.
|
||||
reserveR15ForAsm = false;
|
||||
|
||||
// ARM/ARM64
|
||||
useBackJump = false;
|
||||
useForwardJump = false;
|
||||
cachePointers = true;
|
||||
cachePointers = !Disabled(JitDisable::CACHE_POINTERS);
|
||||
|
||||
// ARM only
|
||||
downcountInRegister = true;
|
||||
useNEONVFPU = false; // true
|
||||
if (!cpu_info.bNEON)
|
||||
if (!cpu_info.bNEON || Disabled(JitDisable::SIMD))
|
||||
useNEONVFPU = false;
|
||||
|
||||
//ARM64
|
||||
useASIMDVFPU = false; // true
|
||||
useASIMDVFPU = false; // !Disabled(JitDisable::SIMD);
|
||||
|
||||
// Common
|
||||
|
||||
// We can get block linking to work with W^X by doing even more unprotect/re-protect, but let's try without first.
|
||||
// enableBlocklink = !PlatformIsWXExclusive(); // Revert to this line if block linking is slow in W^X mode
|
||||
enableBlocklink = true;
|
||||
enableBlocklink = !Disabled(JitDisable::BLOCKLINK);
|
||||
immBranches = false;
|
||||
continueBranches = false;
|
||||
continueJumps = false;
|
||||
@@ -53,9 +56,13 @@ namespace MIPSComp {
|
||||
useStaticAlloc = false;
|
||||
enablePointerify = false;
|
||||
#if PPSSPP_ARCH(ARM64)
|
||||
useStaticAlloc = true;
|
||||
useStaticAlloc = !Disabled(JitDisable::STATIC_ALLOC);
|
||||
// iOS/etc. may disable at runtime if Memory::base is not nicely aligned.
|
||||
enablePointerify = true;
|
||||
enablePointerify = !Disabled(JitDisable::POINTERIFY);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool JitOptions::Disabled(JitDisable bit) {
|
||||
return (disableFlags & (uint32_t)bit) != 0;
|
||||
}
|
||||
}
|
||||
@@ -173,9 +173,42 @@ namespace MIPSComp {
|
||||
}
|
||||
};
|
||||
|
||||
enum class JitDisable {
|
||||
ALU = 0x0001,
|
||||
ALU_IMM = 0x0002,
|
||||
ALU_BIT = 0x0004,
|
||||
MULDIV = 0x0008,
|
||||
|
||||
FPU = 0x0010,
|
||||
FPU_COMP = 0x0040,
|
||||
FPU_XFER = 0x0080,
|
||||
|
||||
VFPU_VEC = 0x0100,
|
||||
VFPU_MTX = 0x0200,
|
||||
VFPU_COMP = 0x0400,
|
||||
VFPU_XFER = 0x0800,
|
||||
|
||||
LSU = 0x1000,
|
||||
LSU_UNALIGNED = 0x2000,
|
||||
LSU_FPU = 0x4000,
|
||||
LSU_VFPU = 0x8000,
|
||||
|
||||
SIMD = 0x00100000,
|
||||
BLOCKLINK = 0x00200000,
|
||||
POINTERIFY = 0x00400000,
|
||||
STATIC_ALLOC = 0x00800000,
|
||||
CACHE_POINTERS = 0x01000000,
|
||||
|
||||
ALL_FLAGS = 0x01FFFFFF,
|
||||
};
|
||||
|
||||
struct JitOptions {
|
||||
JitOptions();
|
||||
|
||||
bool Disabled(JitDisable bit);
|
||||
|
||||
uint32_t disableFlags;
|
||||
|
||||
// x86
|
||||
bool enableVFPUSIMD;
|
||||
bool reserveR15ForAsm;
|
||||
|
||||
@@ -1531,7 +1531,7 @@ skip:
|
||||
}
|
||||
|
||||
// lw, sh, ...
|
||||
if ((opInfo & IN_MEM) || (opInfo & OUT_MEM)) {
|
||||
if (!IsSyscall(op) && (opInfo & (IN_MEM | OUT_MEM)) != 0) {
|
||||
info.isDataAccess = true;
|
||||
switch (opInfo & MEMTYPE_MASK) {
|
||||
case MEMTYPE_BYTE:
|
||||
|
||||
+10
-10
@@ -40,8 +40,8 @@ using namespace MIPSAnalyst;
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
// #define CONDITIONAL_DISABLE(ignore) { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp
|
||||
@@ -74,7 +74,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_IType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_IMM);
|
||||
s32 simm = (s32)_IMM16; // sign extension
|
||||
u32 uimm = op & 0xFFFF;
|
||||
u32 suimm = (u32)(s32)simm;
|
||||
@@ -197,7 +197,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_RType2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -378,7 +378,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_RType3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -668,7 +668,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_ShiftType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU);
|
||||
int rs = (op>>21) & 0x1F;
|
||||
MIPSGPReg rd = _RD;
|
||||
int fd = (op>>6) & 0x1F;
|
||||
@@ -696,7 +696,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_Special3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -786,7 +786,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_Allegrex(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
@@ -894,7 +894,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_Allegrex2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE
|
||||
CONDITIONAL_DISABLE(ALU_BIT);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
@@ -938,7 +938,7 @@ namespace MIPSComp
|
||||
|
||||
void Jit::Comp_MulDivType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(MULDIV);
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
@@ -86,7 +86,7 @@ void Jit::CompFPTriArith(MIPSOpcode op, void (XEmitter::*arith)(X64Reg reg, OpAr
|
||||
}
|
||||
|
||||
void Jit::Comp_FPU3op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
switch (op & 0x3f) {
|
||||
case 0: CompFPTriArith(op, &XEmitter::ADDSS, false); break; //F(fd) = F(fs) + F(ft); //add
|
||||
case 1: CompFPTriArith(op, &XEmitter::SUBSS, true); break; //F(fd) = F(fs) - F(ft); //sub
|
||||
@@ -99,7 +99,7 @@ void Jit::Comp_FPU3op(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_FPULS(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_FPU);
|
||||
s32 offset = _IMM16;
|
||||
int ft = _FT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -174,7 +174,7 @@ void Jit::CompFPComp(int lhs, int rhs, u8 compare, bool allowNaN) {
|
||||
}
|
||||
|
||||
void Jit::Comp_FPUComp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_COMP);
|
||||
|
||||
int fs = _FS;
|
||||
int ft = _FT;
|
||||
@@ -226,7 +226,7 @@ void Jit::Comp_FPUComp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_FPU2op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU);
|
||||
|
||||
int fs = _FS;
|
||||
int fd = _FD;
|
||||
@@ -355,7 +355,7 @@ void Jit::Comp_FPU2op(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_mxc1(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(FPU_XFER);
|
||||
|
||||
int fs = _FS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
namespace MIPSComp {
|
||||
@@ -50,7 +50,7 @@ namespace MIPSComp {
|
||||
|
||||
void Jit::CompITypeMemRead(MIPSOpcode op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), const void *safeFunc)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
int offset = _IMM16;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -81,7 +81,7 @@ namespace MIPSComp {
|
||||
|
||||
void Jit::CompITypeMemWrite(MIPSOpcode op, u32 bits, const void *safeFunc)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
int offset = _IMM16;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -137,7 +137,7 @@ namespace MIPSComp {
|
||||
|
||||
void Jit::CompITypeMemUnpairedLR(MIPSOpcode op, bool isStore)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
int o = op>>26;
|
||||
int offset = _IMM16;
|
||||
MIPSGPReg rt = _RT;
|
||||
@@ -193,7 +193,7 @@ namespace MIPSComp {
|
||||
|
||||
void Jit::CompITypeMemUnpairedLRInner(MIPSOpcode op, X64Reg shiftReg)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
int o = op>>26;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
@@ -285,7 +285,7 @@ namespace MIPSComp {
|
||||
|
||||
void Jit::Comp_ITypeMem(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU);
|
||||
int offset = _IMM16;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
@@ -334,7 +334,7 @@ namespace MIPSComp {
|
||||
MIPSOpcode nextOp = GetOffsetInstruction(1);
|
||||
// Looking for lwr rd, offset-3(rs) which makes a pair.
|
||||
u32 desiredOp = ((op & 0xFFFF0000) + (4 << 26)) + (offset - 3);
|
||||
if (!js.inDelaySlot && nextOp == desiredOp)
|
||||
if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED))
|
||||
{
|
||||
EatInstruction(nextOp);
|
||||
// nextOp has the correct address.
|
||||
@@ -350,7 +350,7 @@ namespace MIPSComp {
|
||||
MIPSOpcode nextOp = GetOffsetInstruction(1);
|
||||
// Looking for lwl rd, offset+3(rs) which makes a pair.
|
||||
u32 desiredOp = ((op & 0xFFFF0000) - (4 << 26)) + (offset + 3);
|
||||
if (!js.inDelaySlot && nextOp == desiredOp)
|
||||
if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED))
|
||||
{
|
||||
EatInstruction(nextOp);
|
||||
// op has the correct address.
|
||||
@@ -366,7 +366,7 @@ namespace MIPSComp {
|
||||
MIPSOpcode nextOp = GetOffsetInstruction(1);
|
||||
// Looking for swr rd, offset-3(rs) which makes a pair.
|
||||
u32 desiredOp = ((op & 0xFFFF0000) + (4 << 26)) + (offset - 3);
|
||||
if (!js.inDelaySlot && nextOp == desiredOp)
|
||||
if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED))
|
||||
{
|
||||
EatInstruction(nextOp);
|
||||
// nextOp has the correct address.
|
||||
@@ -382,7 +382,7 @@ namespace MIPSComp {
|
||||
MIPSOpcode nextOp = GetOffsetInstruction(1);
|
||||
// Looking for swl rd, offset+3(rs) which makes a pair.
|
||||
u32 desiredOp = ((op & 0xFFFF0000) - (4 << 26)) + (offset + 3);
|
||||
if (!js.inDelaySlot && nextOp == desiredOp)
|
||||
if (!js.inDelaySlot && nextOp == desiredOp && !jo.Disabled(JitDisable::LSU_UNALIGNED))
|
||||
{
|
||||
EatInstruction(nextOp);
|
||||
// op has the correct address.
|
||||
|
||||
+36
-36
@@ -42,7 +42,7 @@
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocks(); Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { fpr.ReleaseSpillLocks(); Comp_Generic(op); return; }
|
||||
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
@@ -74,7 +74,7 @@ alignas(16) const float identityMatrix[4][4] = { { 1.0f, 0, 0, 0 }, { 0, 1.0f, 0
|
||||
|
||||
void Jit::Comp_VPFX(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int data = op & 0xFFFFF;
|
||||
int regnum = (op >> 24) & 3;
|
||||
switch (regnum) {
|
||||
@@ -239,7 +239,7 @@ bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[]
|
||||
alignas(16) static u32 ssLoadStoreTemp;
|
||||
|
||||
void Jit::Comp_SV(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
|
||||
s32 imm = (signed short)(op&0xFFFC);
|
||||
int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5);
|
||||
@@ -294,7 +294,7 @@ void Jit::Comp_SV(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_SVQ(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(LSU_VFPU);
|
||||
|
||||
int imm = (signed short)(op&0xFFFC);
|
||||
int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5);
|
||||
@@ -502,7 +502,7 @@ void Jit::Comp_SVQ(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VVectorInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -557,7 +557,7 @@ void Jit::Comp_VVectorInit(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VIdt(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -608,7 +608,7 @@ void Jit::Comp_VIdt(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VDot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -739,7 +739,7 @@ void Jit::Comp_VDot(MIPSOpcode op) {
|
||||
|
||||
|
||||
void Jit::Comp_VHdp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -788,7 +788,7 @@ void Jit::Comp_VHdp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VCrossQuat(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -921,7 +921,7 @@ void Jit::Comp_VCrossQuat(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vcmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -997,7 +997,7 @@ static s32 DoVmaxSS(s32 treg) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VecDo3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1269,7 +1269,7 @@ alignas(16) static const u32 vcmpMask[4][4] = {
|
||||
};
|
||||
|
||||
void Jit::Comp_Vcmp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1512,7 +1512,7 @@ extern const float mulTableVi2f[32] = {
|
||||
};
|
||||
|
||||
void Jit::Comp_Vi2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1599,7 +1599,7 @@ void Jit::Comp_Vi2f(MIPSOpcode op) {
|
||||
|
||||
// Translation of ryg's half_to_float5_SSE2
|
||||
void Jit::Comp_Vh2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1688,7 +1688,7 @@ alignas(16) static s8 vc2i_shuffle[16] = { -1, -1, -1, 0, -1, -1, -1, 1, -1, -
|
||||
alignas(16) static s8 vuc2i_shuffle[16] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
void Jit::Comp_Vx2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1811,7 +1811,7 @@ static const float half = 0.5f;
|
||||
static const double maxMinIntAsDouble[2] = { (double)0x7fffffff, (double)(int)0x80000000 }; // that's not equal to 0x80000000
|
||||
|
||||
void Jit::Comp_Vf2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -1920,7 +1920,7 @@ void Jit::Comp_Vf2i(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vcst(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -1957,7 +1957,7 @@ void Jit::Comp_Vcst(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vsgn(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -2018,7 +2018,7 @@ void Jit::Comp_Vsgn(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vocp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -2067,7 +2067,7 @@ void Jit::Comp_Vocp(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vbfy(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -2181,7 +2181,7 @@ void SinCosNegSin(SinCosArg angle, float *output) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VV2Op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -2419,7 +2419,7 @@ void Jit::Comp_VV2Op(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Mftv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int imm = op & 0xFF;
|
||||
MIPSGPReg rt = _RT;
|
||||
@@ -2509,7 +2509,7 @@ void Jit::Comp_Mftv(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmfvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
@@ -2525,7 +2525,7 @@ void Jit::Comp_Vmfvc(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmtvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
@@ -2549,7 +2549,7 @@ void Jit::Comp_Vmtvc(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VMatrixInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -2632,7 +2632,7 @@ void Jit::Comp_VMatrixInit(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// TODO: This probably ignores prefixes?
|
||||
if (js.HasUnknownPrefix())
|
||||
@@ -2718,7 +2718,7 @@ void Jit::Comp_Vmmov(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_VScl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -2780,7 +2780,7 @@ void Jit::Comp_VScl(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmmul(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// TODO: This probably ignores prefixes?
|
||||
if (js.HasUnknownPrefix())
|
||||
@@ -2974,7 +2974,7 @@ void Jit::Comp_Vmmul(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmscl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// TODO: This op probably ignores prefixes?
|
||||
if (js.HasUnknownPrefix())
|
||||
@@ -3020,7 +3020,7 @@ void Jit::Comp_Vmscl(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vtfm(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
|
||||
// TODO: This probably ignores prefixes? Or maybe uses D?
|
||||
if (js.HasUnknownPrefix())
|
||||
@@ -3163,7 +3163,7 @@ alignas(16) static const s8 vi2xc_shuffle[16] = { 3, 7, 11, 15, -1, -1, -1, -1,
|
||||
alignas(16) static const s8 vi2xs_shuffle[16] = { 2, 3, 6, 7, 10, 11, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
void Jit::Comp_Vi2x(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
@@ -3295,7 +3295,7 @@ void Jit::Comp_Vi2x(MIPSOpcode op) {
|
||||
alignas(16) static const float vavg_table[4] = { 1.0f, 1.0f / 2.0f, 1.0f / 3.0f, 1.0f / 4.0f };
|
||||
|
||||
void Jit::Comp_Vhoriz(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -3412,7 +3412,7 @@ void Jit::Comp_Vhoriz(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Viim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -3435,7 +3435,7 @@ void Jit::Comp_Viim(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_Vfim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
@@ -3497,7 +3497,7 @@ void Jit::CompVrotShuffle(u8 *dregs, int imm, int n, bool negSin) {
|
||||
|
||||
// Very heavily used by FF:CC
|
||||
void Jit::Comp_VRot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
@@ -3569,7 +3569,7 @@ void Jit::Comp_VRot(MIPSOpcode op) {
|
||||
}
|
||||
|
||||
void Jit::Comp_ColorConv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
DISABLE;
|
||||
|
||||
|
||||
+2
-2
@@ -458,12 +458,12 @@ namespace Reporting
|
||||
bool IsSupported()
|
||||
{
|
||||
// Disabled when using certain hacks, because they make for poor reports.
|
||||
if (g_Config.bTimerHack)
|
||||
return false;
|
||||
if (CheatsInEffect())
|
||||
return false;
|
||||
if (g_Config.iLockedCPUSpeed != 0)
|
||||
return false;
|
||||
if (g_Config.uJitDisableFlags != 0)
|
||||
return false;
|
||||
// Don't allow builds without version info from git. They're useless for reporting.
|
||||
if (strcmp(PPSSPP_GIT_VERSION, "unknown") == 0)
|
||||
return false;
|
||||
|
||||
@@ -241,6 +241,7 @@ namespace SaveState
|
||||
static bool needsProcess = false;
|
||||
static std::vector<Operation> pending;
|
||||
static std::mutex mutex;
|
||||
static int screenshotFailures = 0;
|
||||
static bool hasLoadedState = false;
|
||||
static const int STALE_STATE_USES = 2;
|
||||
// 4 hours of total gameplay since the virtual PSP started the game.
|
||||
@@ -250,6 +251,7 @@ namespace SaveState
|
||||
|
||||
// TODO: Should this be configurable?
|
||||
static const int REWIND_NUM_STATES = 20;
|
||||
static const int SCREENSHOT_FAILURE_RETRIES = 15;
|
||||
static StateRingbuffer rewindStates(REWIND_NUM_STATES);
|
||||
// TODO: Any reason for this to be configurable?
|
||||
const static float rewindMaxWallFrequency = 1.0f;
|
||||
@@ -857,6 +859,12 @@ namespace SaveState
|
||||
callbackResult = tempResult ? Status::SUCCESS : Status::FAILURE;
|
||||
if (!tempResult) {
|
||||
ERROR_LOG(SAVESTATE, "Failed to take a screenshot for the savestate! %s", op.filename.c_str());
|
||||
if (screenshotFailures++ < SCREENSHOT_FAILURE_RETRIES) {
|
||||
// Requeue for next frame.
|
||||
SaveScreenshot(op.filename, op.callback, op.cbUserData);
|
||||
}
|
||||
} else {
|
||||
screenshotFailures = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang
|
||||
WRITE(p, "precision mediump float;\n");
|
||||
WRITE(p, "precision highp int;\n");
|
||||
} else {
|
||||
WRITE(p, "#version 330\n");
|
||||
WRITE(p, "#version %d\n", gl_extensions.GLSLVersion());
|
||||
}
|
||||
WRITE(p, "in vec2 v_texcoord0;\n");
|
||||
WRITE(p, "out vec4 fragColor0;\n");
|
||||
@@ -252,7 +252,7 @@ void GenerateDepalShaderFloat(char *buffer, GEBufferFormat pixelFormat, ShaderLa
|
||||
WRITE(p, "#version 100\n");
|
||||
WRITE(p, "precision mediump float;\n");
|
||||
} else {
|
||||
WRITE(p, "#version 110\n");
|
||||
WRITE(p, "#version %d\n", gl_extensions.GLSLVersion());
|
||||
}
|
||||
WRITE(p, "varying vec2 v_texcoord0;\n");
|
||||
WRITE(p, "uniform sampler2D tex;\n");
|
||||
|
||||
@@ -521,7 +521,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) {
|
||||
decodedVerts += indexUpperBound - indexLowerBound + 1;
|
||||
|
||||
bool clockwise = true;
|
||||
if (dc.cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != dc.cullMode) {
|
||||
if (gstate.isCullEnabled() && gstate.getCullMode() != dc.cullMode) {
|
||||
clockwise = false;
|
||||
}
|
||||
indexGen.AddPrim(dc.prim, dc.vertexCount, clockwise);
|
||||
@@ -549,7 +549,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) {
|
||||
case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT:
|
||||
for (int j = i; j <= lastMatch; j++) {
|
||||
bool clockwise = true;
|
||||
if (drawCalls[j].cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
|
||||
if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
|
||||
clockwise = false;
|
||||
}
|
||||
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound, clockwise);
|
||||
@@ -558,7 +558,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) {
|
||||
case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT:
|
||||
for (int j = i; j <= lastMatch; j++) {
|
||||
bool clockwise = true;
|
||||
if (drawCalls[j].cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
|
||||
if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
|
||||
clockwise = false;
|
||||
}
|
||||
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16_le *)drawCalls[j].inds, indexLowerBound, clockwise);
|
||||
@@ -567,7 +567,7 @@ void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) {
|
||||
case GE_VTYPE_IDX_32BIT >> GE_VTYPE_IDX_SHIFT:
|
||||
for (int j = i; j <= lastMatch; j++) {
|
||||
bool clockwise = true;
|
||||
if (drawCalls[j].cullMode != -1 && gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
|
||||
if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
|
||||
clockwise = false;
|
||||
}
|
||||
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u32_le *)drawCalls[j].inds, indexLowerBound, clockwise);
|
||||
@@ -731,10 +731,30 @@ void DrawEngineCommon::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim,
|
||||
}
|
||||
|
||||
if (prim == GE_PRIM_RECTANGLES && (gstate.getTextureAddress(0) & 0x3FFFFFFF) == (gstate.getFrameBufAddress() & 0x3FFFFFFF)) {
|
||||
// Rendertarget == texture?
|
||||
if (!g_Config.bDisableSlowFramebufEffects) {
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
|
||||
DispatchFlush();
|
||||
// Rendertarget == texture? Shouldn't happen. Still, try some mitigations.
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
|
||||
DispatchFlush();
|
||||
}
|
||||
}
|
||||
|
||||
void TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType) {
|
||||
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
|
||||
bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0;
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
memcpy(pos, points[i]->pos.AsArray(), 3 * sizeof(float));
|
||||
pos += posStride;
|
||||
}
|
||||
if (hasTexCoord) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
memcpy(tex, points[i]->uv, 2 * sizeof(float));
|
||||
tex += texStride;
|
||||
}
|
||||
}
|
||||
if (hasColor) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
memcpy(col, Vec4f::FromRGBA(points[i]->color_32).AsArray(), 4 * sizeof(float));
|
||||
col += colStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace Spline { struct Weight2D; }
|
||||
|
||||
class TessellationDataTransfer {
|
||||
public:
|
||||
virtual ~TessellationDataTransfer() {}
|
||||
void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType);
|
||||
virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) = 0;
|
||||
};
|
||||
@@ -74,15 +75,15 @@ public:
|
||||
// This would seem to be unnecessary now, but is still required for splines/beziers to work in the software backend since SubmitPrim
|
||||
// is different. Should probably refactor that.
|
||||
// Note that vertTypeID should be computed using GetVertTypeID().
|
||||
virtual void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int *bytesRead) {
|
||||
SubmitPrim(verts, inds, prim, vertexCount, vertTypeID, -1, bytesRead);
|
||||
virtual void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead) {
|
||||
SubmitPrim(verts, inds, prim, vertexCount, vertTypeID, cullMode, bytesRead);
|
||||
}
|
||||
|
||||
bool TestBoundingBox(void* control_points, int vertexCount, u32 vertType, int *bytesRead);
|
||||
|
||||
void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead);
|
||||
void SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead);
|
||||
void SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead);
|
||||
template<class Surface>
|
||||
void SubmitCurve(const void *control_points, const void *indices, Surface &surface, u32 vertType, int *bytesRead, const char *scope);
|
||||
void ClearSplineBezierWeights();
|
||||
|
||||
std::vector<std::string> DebugGetVertexLoaderIDs();
|
||||
@@ -130,7 +131,6 @@ protected:
|
||||
// Vertex collector buffers
|
||||
u8 *decoded = nullptr;
|
||||
u16 *decIndex = nullptr;
|
||||
u8 *splineBuffer = nullptr;
|
||||
|
||||
// Cached vertex decoders
|
||||
u32 lastVType_ = -1;
|
||||
|
||||
+137
-129
@@ -39,6 +39,7 @@
|
||||
#include "GPU/Common/FramebufferCommon.h"
|
||||
#include "GPU/Common/PostShader.h"
|
||||
#include "GPU/Common/TextureCacheCommon.h"
|
||||
#include "GPU/Debugger/Record.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
@@ -147,14 +148,13 @@ void FramebufferManagerCommon::Init() {
|
||||
|
||||
bool FramebufferManagerCommon::UpdateSize() {
|
||||
const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight;
|
||||
const bool newSettings = bloomHack_ != g_Config.iBloomHack || trueColor_ != g_Config.bTrueColor || useBufferedRendering_ != (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
|
||||
const bool newSettings = bloomHack_ != g_Config.iBloomHack || useBufferedRendering_ != (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
|
||||
|
||||
renderWidth_ = (float)PSP_CoreParameter().renderWidth;
|
||||
renderHeight_ = (float)PSP_CoreParameter().renderHeight;
|
||||
pixelWidth_ = PSP_CoreParameter().pixelWidth;
|
||||
pixelHeight_ = PSP_CoreParameter().pixelHeight;
|
||||
bloomHack_ = g_Config.iBloomHack;
|
||||
trueColor_ = g_Config.bTrueColor;
|
||||
useBufferedRendering_ = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
|
||||
return newRender || newSettings;
|
||||
@@ -169,27 +169,24 @@ void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, G
|
||||
displayFramebufPtr_ = framebuf;
|
||||
displayStride_ = stride;
|
||||
displayFormat_ = format;
|
||||
GPURecord::NotifyDisplay(framebuf, stride, format);
|
||||
}
|
||||
|
||||
VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) {
|
||||
addr &= 0x3FFFFFFF;
|
||||
VirtualFramebuffer *match = nullptr;
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
VirtualFramebuffer *v = vfbs_[i];
|
||||
if (MaskedEqual(v->fb_address, addr)) {
|
||||
if (v->fb_address == addr) {
|
||||
// Could check w too but whatever
|
||||
if (match == nullptr || match->last_frame_render < v->last_frame_render) {
|
||||
match = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
bool FramebufferManagerCommon::MaskedEqual(u32 addr1, u32 addr2) {
|
||||
return (addr1 & 0x03FFFFFF) == (addr2 & 0x03FFFFFF);
|
||||
}
|
||||
|
||||
u32 FramebufferManagerCommon::FramebufferByteSize(const VirtualFramebuffer *vfb) const {
|
||||
return vfb->fb_stride * vfb->height * (vfb->format == GE_FORMAT_8888 ? 4 : 2);
|
||||
}
|
||||
@@ -255,11 +252,10 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma
|
||||
|
||||
if (viewport_width != region_width) {
|
||||
// The majority of the time, these are equal. If not, let's check what we know.
|
||||
const u32 fb_normalized_address = fb_address | 0x44000000;
|
||||
u32 nearest_address = 0xFFFFFFFF;
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
const u32 other_address = vfbs_[i]->fb_address | 0x44000000;
|
||||
if (other_address > fb_normalized_address && other_address < nearest_address) {
|
||||
const u32 other_address = vfbs_[i]->fb_address & 0x3FFFFFFF;
|
||||
if (other_address > fb_address && other_address < nearest_address) {
|
||||
nearest_address = other_address;
|
||||
}
|
||||
}
|
||||
@@ -268,7 +264,7 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma
|
||||
// This catches some cases where we can know this.
|
||||
// Hmm. The problem is that we could only catch it for the first of two buffers...
|
||||
const u32 bpp = fb_format == GE_FORMAT_8888 ? 4 : 2;
|
||||
int avail_height = (nearest_address - fb_normalized_address) / (fb_stride * bpp);
|
||||
int avail_height = (nearest_address - fb_address) / (fb_stride * bpp);
|
||||
if (avail_height < drawing_height && avail_height == region_height) {
|
||||
drawing_width = std::min(region_width, fb_stride);
|
||||
drawing_height = avail_height;
|
||||
@@ -284,11 +280,10 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferForma
|
||||
}
|
||||
|
||||
void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate) {
|
||||
params->fb_addr = gstate.getFrameBufAddress();
|
||||
params->fb_address = gstate.getFrameBufRawAddress();
|
||||
params->fb_address = (gstate.getFrameBufRawAddress() & 0x3FFFFFFF) | 0x04000000; // GetFramebufferHeuristicInputs is only called from rendering, and thus, it's VRAM.
|
||||
params->fb_stride = gstate.FrameBufStride();
|
||||
|
||||
params->z_address = gstate.getDepthBufRawAddress();
|
||||
params->z_address = (gstate.getDepthBufRawAddress() & 0x3FFFFFFF) | 0x04000000;
|
||||
params->z_stride = gstate.DepthBufStride();
|
||||
|
||||
params->fmt = gstate.FrameBufFormat();
|
||||
@@ -350,6 +345,13 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||
vfb->fb_stride = params.fb_stride;
|
||||
vfb->format = params.fmt;
|
||||
}
|
||||
|
||||
if (vfb->z_address == 0 && vfb->z_stride == 0) {
|
||||
// Got one that was created by CreateRAMFramebuffer. Since it has no depth buffer,
|
||||
// we just recreate it immediately.
|
||||
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
|
||||
}
|
||||
|
||||
// Keep track, but this isn't really used.
|
||||
vfb->z_stride = params.z_stride;
|
||||
// Heuristic: In throughmode, a higher height could be used. Let's avoid shrinking the buffer.
|
||||
@@ -420,8 +422,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||
|
||||
// None found? Create one.
|
||||
if (!vfb) {
|
||||
vfb = new VirtualFramebuffer();
|
||||
memset(vfb, 0, sizeof(VirtualFramebuffer));
|
||||
vfb = new VirtualFramebuffer{};
|
||||
vfb->fbo = nullptr;
|
||||
vfb->fb_address = params.fb_address;
|
||||
vfb->fb_stride = params.fb_stride;
|
||||
@@ -442,9 +443,9 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||
SetColorUpdated(vfb, skipDrawReason);
|
||||
|
||||
u32 byteSize = FramebufferByteSize(vfb);
|
||||
u32 fb_address_mem = (params.fb_address & 0x3FFFFFFF) | 0x04000000;
|
||||
if (Memory::IsVRAMAddress(fb_address_mem) && fb_address_mem + byteSize > framebufRangeEnd_) {
|
||||
framebufRangeEnd_ = fb_address_mem + byteSize;
|
||||
// FB heuristics always produce an address in VRAM (this is during rendering) so we don't need to poke in the 0x04000000 flag here.
|
||||
if (Memory::IsVRAMAddress(params.fb_address) && params.fb_address + byteSize > framebufRangeEnd_) {
|
||||
framebufRangeEnd_ = params.fb_address + byteSize;
|
||||
}
|
||||
|
||||
ResizeFramebufFBO(vfb, drawing_width, drawing_height, true);
|
||||
@@ -458,8 +459,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||
currentRenderVfb_ = vfb;
|
||||
|
||||
if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) {
|
||||
gpu->PerformMemoryUpload(fb_address_mem, byteSize);
|
||||
NotifyStencilUpload(fb_address_mem, byteSize, true);
|
||||
gpu->PerformMemoryUpload(params.fb_address, byteSize);
|
||||
NotifyStencilUpload(params.fb_address, byteSize, true);
|
||||
// TODO: Is it worth trying to upload the depth buffer?
|
||||
}
|
||||
|
||||
@@ -589,7 +590,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
|
||||
shaderManager_->DirtyLastShader();
|
||||
|
||||
// Copy depth pixel value from the read framebuffer to the draw framebuffer
|
||||
if (prevVfb && !g_Config.bDisableSlowFramebufEffects) {
|
||||
if (prevVfb) {
|
||||
bool hasNewerDepth = prevVfb->last_frame_depth_render != 0 && prevVfb->last_frame_depth_render >= vfb->last_frame_depth_updated;
|
||||
if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !hasNewerDepth || isClearingDepth) {
|
||||
// If depth wasn't updated, then we're at least "two degrees" away from the data.
|
||||
@@ -682,7 +683,8 @@ void FramebufferManagerCommon::NotifyVideoUpload(u32 addr, int size, int width,
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) {
|
||||
addr &= ~0x40000000;
|
||||
// Take off the uncached flag from the address. Not to be confused with the start of VRAM.
|
||||
addr &= 0x3FFFFFFF;
|
||||
// TODO: Could go through all FBOs, but probably not important?
|
||||
// TODO: Could also check for inner changes, but video is most important.
|
||||
bool isDisplayBuf = addr == DisplayFramebufAddr() || addr == PrevDisplayFramebufAddr();
|
||||
@@ -693,7 +695,7 @@ void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) {
|
||||
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
VirtualFramebuffer *vfb = vfbs_[i];
|
||||
if (MaskedEqual(vfb->fb_address, addr)) {
|
||||
if (vfb->fb_address == addr) {
|
||||
FlushBeforeCopy();
|
||||
|
||||
if (useBufferedRendering_ && vfb->fbo) {
|
||||
@@ -702,7 +704,7 @@ void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size, bool safe) {
|
||||
// If we're not rendering to it, format may be wrong. Use displayFormat_ instead.
|
||||
fmt = displayFormat_;
|
||||
}
|
||||
DrawPixels(vfb, 0, 0, Memory::GetPointer(addr | 0x04000000), fmt, vfb->fb_stride, vfb->width, vfb->height);
|
||||
DrawPixels(vfb, 0, 0, Memory::GetPointer(addr), fmt, vfb->fb_stride, vfb->width, vfb->height);
|
||||
SetColorUpdated(vfb, gstate_c.skipDrawReason);
|
||||
} else {
|
||||
INFO_LOG(FRAMEBUF, "Invalidating FBO for %08x (%i x %i x %i)", vfb->fb_address, vfb->width, vfb->height, vfb->format);
|
||||
@@ -868,11 +870,13 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
|
||||
VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_);
|
||||
if (!vfb) {
|
||||
// Let's search for a framebuf within this range.
|
||||
const u32 addr = (displayFramebufPtr_ & 0x03FFFFFF) | 0x04000000;
|
||||
// Let's search for a framebuf within this range. Note that we also look for
|
||||
// "framebuffers" sitting in RAM so we only take off the kernel and uncached bits of the address
|
||||
// when comparing.
|
||||
const u32 addr = displayFramebufPtr_ & 0x3FFFFFFF;
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
VirtualFramebuffer *v = vfbs_[i];
|
||||
const u32 v_addr = (v->fb_address & 0x03FFFFFF) | 0x04000000;
|
||||
const u32 v_addr = v->fb_address & 0x3FFFFFFF;
|
||||
const u32 v_size = FramebufferByteSize(v);
|
||||
if (addr >= v_addr && addr < v_addr + v_size) {
|
||||
const u32 dstBpp = v->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
@@ -909,14 +913,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
if (!vfb) {
|
||||
if (Memory::IsValidAddress(displayFramebufPtr_)) {
|
||||
// The game is displaying something directly from RAM. In GTA, it's decoded video.
|
||||
|
||||
// First check that it's not a known RAM copy of a VRAM framebuffer though, as in MotoGP
|
||||
for (auto iter = knownFramebufferRAMCopies_.begin(); iter != knownFramebufferRAMCopies_.end(); ++iter) {
|
||||
if (iter->second == displayFramebufPtr_) {
|
||||
vfb = GetVFBAt(iter->first);
|
||||
}
|
||||
}
|
||||
|
||||
if (!vfb) {
|
||||
shaderManager_->DirtyLastShader();
|
||||
if (useBufferedRendering_) {
|
||||
@@ -1156,30 +1152,10 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
||||
|
||||
SetRenderSize(vfb);
|
||||
|
||||
bool trueColor = trueColor_;
|
||||
if (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x00154000) {
|
||||
trueColor = true;
|
||||
}
|
||||
|
||||
if (trueColor) {
|
||||
vfb->colorDepth = Draw::FBO_8888;
|
||||
} else {
|
||||
switch (vfb->format) {
|
||||
case GE_FORMAT_4444:
|
||||
vfb->colorDepth = Draw::FBO_4444;
|
||||
break;
|
||||
case GE_FORMAT_5551:
|
||||
vfb->colorDepth = Draw::FBO_5551;
|
||||
break;
|
||||
case GE_FORMAT_565:
|
||||
vfb->colorDepth = Draw::FBO_565;
|
||||
break;
|
||||
case GE_FORMAT_8888:
|
||||
default:
|
||||
vfb->colorDepth = Draw::FBO_8888;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// During hardware rendering, we always render at full color depth even if the game wouldn't on real hardware.
|
||||
// It's not worth the trouble trying to support lower bit-depth rendering, just
|
||||
// more cases to test that nobody will ever use.
|
||||
vfb->colorDepth = Draw::FBO_8888;
|
||||
|
||||
textureCache_->ForgetLastTexture();
|
||||
|
||||
@@ -1203,7 +1179,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
// GLES resets the blend state on clears.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
if (!skipCopy && !g_Config.bDisableSlowFramebufEffects) {
|
||||
if (!skipCopy) {
|
||||
BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0);
|
||||
}
|
||||
}
|
||||
@@ -1223,6 +1199,8 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
||||
}
|
||||
}
|
||||
|
||||
// This is called from detected memcopies only. Not block transfers.
|
||||
// MotoGP goes this path so we need to catch those copies here.
|
||||
bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, bool isMemset, u32 skipDrawReason) {
|
||||
if (size == 0) {
|
||||
return false;
|
||||
@@ -1243,7 +1221,8 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
continue;
|
||||
}
|
||||
|
||||
const u32 vfb_address = (0x04000000 | vfb->fb_address) & 0x3FFFFFFF;
|
||||
// We only remove the kernel and uncached bits when comparing.
|
||||
const u32 vfb_address = vfb->fb_address & 0x3FFFFFFF;
|
||||
const u32 vfb_size = FramebufferByteSize(vfb);
|
||||
const u32 vfb_bpp = vfb->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
const u32 vfb_byteStride = vfb->fb_stride * vfb_bpp;
|
||||
@@ -1282,15 +1261,6 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
}
|
||||
}
|
||||
|
||||
if (srcBuffer && srcY == 0 && srcH == srcBuffer->height && !dstBuffer) {
|
||||
// MotoGP workaround - it copies a framebuffer to memory and then displays it.
|
||||
// TODO: It's rare anyway, but the game could modify the RAM and then we'd display the wrong thing.
|
||||
// Unfortunately, that would force 1x render resolution.
|
||||
if (Memory::IsRAMAddress(dst)) {
|
||||
knownFramebufferRAMCopies_.insert(std::pair<u32, u32>(src, dst));
|
||||
}
|
||||
}
|
||||
|
||||
if (!useBufferedRendering_) {
|
||||
// If we're copying into a recently used display buf, it's probably destined for the screen.
|
||||
if (srcBuffer || (dstBuffer != displayFramebuf_ && dstBuffer != prevDisplayFramebuf_)) {
|
||||
@@ -1298,17 +1268,23 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
}
|
||||
}
|
||||
|
||||
if (!dstBuffer && srcBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) {
|
||||
dstBuffer = CreateRAMFramebuffer(dst, srcBuffer->width, srcBuffer->height, srcBuffer->fb_stride, srcBuffer->format);
|
||||
dstY = 0;
|
||||
}
|
||||
if (dstBuffer) {
|
||||
dstBuffer->last_frame_used = gpuStats.numFlips;
|
||||
}
|
||||
|
||||
if (dstBuffer && srcBuffer && !isMemset) {
|
||||
if (srcBuffer == dstBuffer) {
|
||||
WARN_LOG_REPORT_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x", src, dst);
|
||||
} else {
|
||||
WARN_LOG_REPORT_ONCE(dstnotsrccpy, G3D, "Inter-buffer memcpy %08x -> %08x", src, dst);
|
||||
// Just do the blit!
|
||||
if (g_Config.bBlockTransferGPU) {
|
||||
BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0);
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
RebindFramebuffer();
|
||||
}
|
||||
BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0);
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
RebindFramebuffer();
|
||||
}
|
||||
return false;
|
||||
} else if (dstBuffer) {
|
||||
@@ -1316,15 +1292,12 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
gpuStats.numClears++;
|
||||
}
|
||||
WARN_LOG_ONCE(btucpy, G3D, "Memcpy fbo upload %08x -> %08x", src, dst);
|
||||
if (g_Config.bBlockTransferGPU) {
|
||||
FlushBeforeCopy();
|
||||
const u8 *srcBase = Memory::GetPointerUnchecked(src);
|
||||
DrawPixels(dstBuffer, 0, dstY, srcBase, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstH);
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
RebindFramebuffer();
|
||||
// This is a memcpy, let's still copy just in case.
|
||||
return false;
|
||||
}
|
||||
FlushBeforeCopy();
|
||||
const u8 *srcBase = Memory::GetPointerUnchecked(src);
|
||||
DrawPixels(dstBuffer, 0, dstY, srcBase, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstH);
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
RebindFramebuffer();
|
||||
// This is a memcpy, let's still copy just in case.
|
||||
return false;
|
||||
} else if (srcBuffer) {
|
||||
WARN_LOG_ONCE(btdcpy, G3D, "Memcpy fbo download %08x -> %08x", src, dst);
|
||||
@@ -1341,7 +1314,8 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const {
|
||||
// Can't be const, in case it has to create a vfb unfortunately.
|
||||
void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) {
|
||||
u32 dstYOffset = -1;
|
||||
u32 dstXOffset = -1;
|
||||
u32 srcYOffset = -1;
|
||||
@@ -1354,7 +1328,7 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst
|
||||
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
VirtualFramebuffer *vfb = vfbs_[i];
|
||||
const u32 vfb_address = (0x04000000 | vfb->fb_address) & 0x3FFFFFFF;
|
||||
const u32 vfb_address = vfb->fb_address & 0x3FFFFFFF;
|
||||
const u32 vfb_size = FramebufferByteSize(vfb);
|
||||
const u32 vfb_bpp = vfb->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
const u32 vfb_byteStride = vfb->fb_stride * vfb_bpp;
|
||||
@@ -1421,6 +1395,16 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst
|
||||
}
|
||||
}
|
||||
|
||||
if (!dstBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) {
|
||||
GEBufferFormat ramFormat = bpp == 4 ? GE_FORMAT_8888 : GE_FORMAT_5551;
|
||||
// TODO: We don't really know the 16-bit format here.. at all. Can only guess when it gets used later!
|
||||
// But actually, the format of the source buffer is probably not a bad guess..
|
||||
dstBuffer = CreateRAMFramebuffer(dstBasePtr, dstWidth, dstHeight, dstStride, ramFormat);
|
||||
}
|
||||
|
||||
if (dstBuffer)
|
||||
dstBuffer->last_frame_used = gpuStats.numFlips;
|
||||
|
||||
if (dstYOffset != (u32)-1) {
|
||||
dstY += dstYOffset;
|
||||
dstX += dstXOffset;
|
||||
@@ -1431,6 +1415,38 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format) {
|
||||
float renderWidthFactor = renderWidth_ / 480.0f;
|
||||
float renderHeightFactor = renderHeight_ / 272.0f;
|
||||
|
||||
// A target for the destination is missing - so just create one!
|
||||
// Make sure this one would be found by the algorithm above so we wouldn't
|
||||
// create a new one each frame.
|
||||
VirtualFramebuffer *vfb = new VirtualFramebuffer{};
|
||||
vfb->fbo = nullptr;
|
||||
vfb->fb_address = fbAddress; // NOTE - not necessarily in VRAM!
|
||||
vfb->fb_stride = stride;
|
||||
vfb->z_address = 0; // marks that if anyone tries to render to this framebuffer, it should be dropped and recreated.
|
||||
vfb->z_stride = 0;
|
||||
vfb->width = std::max(width, stride);
|
||||
vfb->height = height;
|
||||
vfb->newWidth = vfb->width;
|
||||
vfb->newHeight = vfb->height;
|
||||
vfb->lastFrameNewSize = gpuStats.numFlips;
|
||||
vfb->renderWidth = (u16)(vfb->width * renderWidthFactor);
|
||||
vfb->renderHeight = (u16)(vfb->height * renderHeightFactor);
|
||||
vfb->bufferWidth = vfb->width;
|
||||
vfb->bufferHeight = vfb->height;
|
||||
vfb->format = format;
|
||||
vfb->drawnFormat = GE_FORMAT_8888;
|
||||
vfb->usageFlags = FB_USAGE_RENDERTARGET;
|
||||
SetColorUpdated(vfb, 0);
|
||||
textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED);
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth });
|
||||
vfbs_.push_back(vfb);
|
||||
return vfb;
|
||||
}
|
||||
|
||||
// 1:1 pixel sides buffers, we resize buffers to these before we read them back.
|
||||
VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFramebuffer *vfb) {
|
||||
// For now we'll keep these on the same struct as the ones that can get displayed
|
||||
@@ -1619,29 +1635,23 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
|
||||
if (srcBuffer == dstBuffer) {
|
||||
if (srcX != dstX || srcY != dstY) {
|
||||
WARN_LOG_ONCE(dstsrc, G3D, "Intra-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr);
|
||||
if (g_Config.bBlockTransferGPU) {
|
||||
FlushBeforeCopy();
|
||||
BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp);
|
||||
RebindFramebuffer();
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Ignore, nothing to do. Tales of Phantasia X does this by accident.
|
||||
if (g_Config.bBlockTransferGPU) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WARN_LOG_ONCE(dstnotsrc, G3D, "Inter-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr);
|
||||
// Just do the blit!
|
||||
if (g_Config.bBlockTransferGPU) {
|
||||
FlushBeforeCopy();
|
||||
BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp);
|
||||
RebindFramebuffer();
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
return true; // No need to actually do the memory copy behind, probably.
|
||||
return true;
|
||||
} else {
|
||||
// Ignore, nothing to do. Tales of Phantasia X does this by accident.
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
WARN_LOG_ONCE(dstnotsrc, G3D, "Inter-buffer block transfer %08x -> %08x", srcBasePtr, dstBasePtr);
|
||||
// Just do the blit!
|
||||
FlushBeforeCopy();
|
||||
BlitFramebuffer(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, dstWidth, dstHeight, bpp);
|
||||
RebindFramebuffer();
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
return true; // No need to actually do the memory copy behind, probably.
|
||||
}
|
||||
return false;
|
||||
} else if (dstBuffer) {
|
||||
@@ -1699,26 +1709,24 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS
|
||||
|
||||
if (dstBuffer && !srcBuffer) {
|
||||
WARN_LOG_ONCE(btu, G3D, "Block transfer upload %08x -> %08x", srcBasePtr, dstBasePtr);
|
||||
if (g_Config.bBlockTransferGPU) {
|
||||
FlushBeforeCopy();
|
||||
const u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp;
|
||||
int dstBpp = dstBuffer->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
float dstXFactor = (float)bpp / dstBpp;
|
||||
if (dstWidth > dstBuffer->width || dstHeight > dstBuffer->height) {
|
||||
// The buffer isn't big enough, and we have a clear hint of size. Resize.
|
||||
// This happens in Valkyrie Profile when uploading video at the ending.
|
||||
ResizeFramebufFBO(dstBuffer, dstWidth, dstHeight, false, true);
|
||||
// Make sure we don't flop back and forth.
|
||||
dstBuffer->newWidth = std::max(dstWidth, (int)dstBuffer->width);
|
||||
dstBuffer->newHeight = std::max(dstHeight, (int)dstBuffer->height);
|
||||
dstBuffer->lastFrameNewSize = gpuStats.numFlips;
|
||||
// Resizing may change the viewport/etc.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE);
|
||||
}
|
||||
DrawPixels(dstBuffer, static_cast<int>(dstX * dstXFactor), dstY, srcBase, dstBuffer->format, static_cast<int>(srcStride * dstXFactor), static_cast<int>(dstWidth * dstXFactor), dstHeight);
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
RebindFramebuffer();
|
||||
FlushBeforeCopy();
|
||||
const u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp;
|
||||
int dstBpp = dstBuffer->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
float dstXFactor = (float)bpp / dstBpp;
|
||||
if (dstWidth > dstBuffer->width || dstHeight > dstBuffer->height) {
|
||||
// The buffer isn't big enough, and we have a clear hint of size. Resize.
|
||||
// This happens in Valkyrie Profile when uploading video at the ending.
|
||||
ResizeFramebufFBO(dstBuffer, dstWidth, dstHeight, false, true);
|
||||
// Make sure we don't flop back and forth.
|
||||
dstBuffer->newWidth = std::max(dstWidth, (int)dstBuffer->width);
|
||||
dstBuffer->newHeight = std::max(dstHeight, (int)dstBuffer->height);
|
||||
dstBuffer->lastFrameNewSize = gpuStats.numFlips;
|
||||
// Resizing may change the viewport/etc.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE);
|
||||
}
|
||||
DrawPixels(dstBuffer, static_cast<int>(dstX * dstXFactor), dstY, srcBase, dstBuffer->format, static_cast<int>(srcStride * dstXFactor), static_cast<int>(dstWidth * dstXFactor), dstHeight);
|
||||
SetColorUpdated(dstBuffer, skipDrawReason);
|
||||
RebindFramebuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1917,7 +1925,7 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB
|
||||
|
||||
if (!vfb) {
|
||||
// If there's no vfb and we're drawing there, must be memory?
|
||||
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format);
|
||||
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, format);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1971,7 +1979,7 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32
|
||||
|
||||
if (!vfb) {
|
||||
// If there's no vfb and we're drawing there, must be memory?
|
||||
buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT);
|
||||
buffer = GPUDebugBuffer(Memory::GetPointer(z_address), z_stride, 512, GPU_DBG_FORMAT_16BIT);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2007,7 +2015,7 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G
|
||||
if (!vfb) {
|
||||
// If there's no vfb and we're drawing there, must be memory?
|
||||
// TODO: Actually get the stencil.
|
||||
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, GPU_DBG_FORMAT_8888);
|
||||
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, GPU_DBG_FORMAT_8888);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2059,7 +2067,7 @@ void FramebufferManagerCommon::PackFramebufferSync_(VirtualFramebuffer *vfb, int
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 fb_address = (0x04000000) | vfb->fb_address;
|
||||
const u32 fb_address = vfb->fb_address & 0x3FFFFFFF;
|
||||
|
||||
Draw::DataFormat destFormat = GEFormatToThin3D(vfb->format);
|
||||
const int dstBpp = (int)DataFormatSizeInBytes(destFormat);
|
||||
|
||||
@@ -119,7 +119,6 @@ struct VirtualFramebuffer {
|
||||
};
|
||||
|
||||
struct FramebufferHeuristicParams {
|
||||
u32 fb_addr;
|
||||
u32 fb_address;
|
||||
int fb_stride;
|
||||
u32 z_address;
|
||||
@@ -147,6 +146,8 @@ enum BindFramebufferColorFlags {
|
||||
BINDFBCOLOR_MAY_COPY = 1,
|
||||
BINDFBCOLOR_MAY_COPY_WITH_UV = 3,
|
||||
BINDFBCOLOR_APPLY_TEX_OFFSET = 4,
|
||||
// Used when rendering to a temporary surface (e.g. not the current render target.)
|
||||
BINDFBCOLOR_FORCE_SELF = 8,
|
||||
};
|
||||
|
||||
enum DrawTextureFlags {
|
||||
@@ -243,10 +244,10 @@ public:
|
||||
size_t NumVFBs() const { return vfbs_.size(); }
|
||||
|
||||
u32 PrevDisplayFramebufAddr() {
|
||||
return prevDisplayFramebuf_ ? (0x04000000 | prevDisplayFramebuf_->fb_address) : 0;
|
||||
return prevDisplayFramebuf_ ? prevDisplayFramebuf_->fb_address : 0;
|
||||
}
|
||||
u32 DisplayFramebufAddr() {
|
||||
return displayFramebuf_ ? (0x04000000 | displayFramebuf_->fb_address) : 0;
|
||||
return displayFramebuf_ ? displayFramebuf_->fb_address : 0;
|
||||
}
|
||||
|
||||
u32 DisplayFramebufStride() {
|
||||
@@ -332,7 +333,6 @@ protected:
|
||||
|
||||
void EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height);
|
||||
u32 FramebufferByteSize(const VirtualFramebuffer *vfb) const;
|
||||
static bool MaskedEqual(u32 addr1, u32 addr2);
|
||||
|
||||
void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb);
|
||||
void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged);
|
||||
@@ -346,10 +346,12 @@ protected:
|
||||
|
||||
bool ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const;
|
||||
void DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb);
|
||||
void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const;
|
||||
void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp);
|
||||
VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb);
|
||||
virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0;
|
||||
virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0;
|
||||
|
||||
VirtualFramebuffer *CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format);
|
||||
void OptimizeDownloadRange(VirtualFramebuffer *vfb, int &x, int &y, int &w, int &h);
|
||||
|
||||
void UpdateFramebufUsage(VirtualFramebuffer *vfb);
|
||||
@@ -393,7 +395,6 @@ protected:
|
||||
|
||||
std::vector<VirtualFramebuffer *> vfbs_;
|
||||
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
|
||||
std::set<std::pair<u32, u32>> knownFramebufferRAMCopies_;
|
||||
|
||||
bool gameUsesSequentialCopies_ = false;
|
||||
|
||||
@@ -403,7 +404,6 @@ protected:
|
||||
int pixelWidth_;
|
||||
int pixelHeight_;
|
||||
int bloomHack_ = 0;
|
||||
bool trueColor_ = false;
|
||||
|
||||
// Used by post-processing shaders
|
||||
std::vector<Draw::Framebuffer *> extraFBOs_;
|
||||
|
||||
@@ -40,6 +40,17 @@ bool CanUseHardwareTransform(int prim) {
|
||||
return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
|
||||
}
|
||||
|
||||
bool IsStencilTestOutputDisabled() {
|
||||
// The mask applies on all stencil ops.
|
||||
if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) {
|
||||
if (gstate.FrameBufFormat() == GE_FORMAT_565) {
|
||||
return true;
|
||||
}
|
||||
return gstate.getStencilOpZPass() == GE_STENCILOP_KEEP && gstate.getStencilOpZFail() == GE_STENCILOP_KEEP && gstate.getStencilOpSFail() == GE_STENCILOP_KEEP;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NeedsTestDiscard() {
|
||||
// We assume this is called only when enabled and not trivially true (may also be for color testing.)
|
||||
if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF)
|
||||
@@ -170,7 +181,7 @@ const bool nonAlphaDestFactors[16] = {
|
||||
};
|
||||
|
||||
ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) {
|
||||
if (!gstate.isStencilTestEnabled() || gstate.isModeClear()) {
|
||||
if (IsStencilTestOutputDisabled() || gstate.isModeClear()) {
|
||||
return REPLACE_ALPHA_NO;
|
||||
}
|
||||
|
||||
@@ -510,7 +521,7 @@ float DepthSliceFactor() {
|
||||
}
|
||||
|
||||
// This is used for float values which might not be integers, but are in the integer scale of 65535.
|
||||
static float ToScaledDepthFromInteger(float z) {
|
||||
float ToScaledDepthFromIntegerScale(float z) {
|
||||
if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) {
|
||||
return z * (1.0f / 65535.0f);
|
||||
}
|
||||
@@ -526,10 +537,6 @@ static float ToScaledDepthFromInteger(float z) {
|
||||
}
|
||||
}
|
||||
|
||||
float ToScaledDepth(u16 z) {
|
||||
return ToScaledDepthFromInteger((float)(int)z);
|
||||
}
|
||||
|
||||
float FromScaledDepth(float z) {
|
||||
if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) {
|
||||
return z * 65535.0f;
|
||||
@@ -595,8 +602,8 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
||||
out.viewportY = renderY + displayOffsetY;
|
||||
out.viewportW = curRTWidth * renderWidthFactor;
|
||||
out.viewportH = curRTHeight * renderHeightFactor;
|
||||
out.depthRangeMin = ToScaledDepthFromInteger(0);
|
||||
out.depthRangeMax = ToScaledDepthFromInteger(65536);
|
||||
out.depthRangeMin = ToScaledDepthFromIntegerScale(0);
|
||||
out.depthRangeMax = ToScaledDepthFromIntegerScale(65536);
|
||||
} else {
|
||||
// These we can turn into a glViewport call, offset by offsetX and offsetY. Math after.
|
||||
float vpXScale = gstate.getViewportXScale();
|
||||
@@ -705,11 +712,11 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
||||
if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) {
|
||||
zScale = 1.0f;
|
||||
zOffset = 0.0f;
|
||||
out.depthRangeMin = ToScaledDepthFromInteger(vpZCenter - vpZScale);
|
||||
out.depthRangeMax = ToScaledDepthFromInteger(vpZCenter + vpZScale);
|
||||
out.depthRangeMin = ToScaledDepthFromIntegerScale(vpZCenter - vpZScale);
|
||||
out.depthRangeMax = ToScaledDepthFromIntegerScale(vpZCenter + vpZScale);
|
||||
} else {
|
||||
out.depthRangeMin = ToScaledDepthFromInteger(minz);
|
||||
out.depthRangeMax = ToScaledDepthFromInteger(maxz);
|
||||
out.depthRangeMin = ToScaledDepthFromIntegerScale(minz);
|
||||
out.depthRangeMax = ToScaledDepthFromIntegerScale(maxz);
|
||||
}
|
||||
|
||||
// OpenGL will clamp these for us anyway, and Direct3D will error if not clamped.
|
||||
@@ -996,7 +1003,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) {
|
||||
|
||||
int constantAlpha = 255;
|
||||
BlendFactor constantAlphaGL = BlendFactor::ONE;
|
||||
if (gstate.isStencilTestEnabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) {
|
||||
if (!IsStencilTestOutputDisabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) {
|
||||
switch (ReplaceAlphaWithStencilType()) {
|
||||
case STENCIL_VALUE_UNIFORM:
|
||||
constantAlpha = gstate.getStencilTestRef();
|
||||
@@ -1164,7 +1171,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) {
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ZERO);
|
||||
break;
|
||||
}
|
||||
} else if (gstate.isStencilTestEnabled()) {
|
||||
} else if (!IsStencilTestOutputDisabled()) {
|
||||
switch (ReplaceAlphaWithStencilType()) {
|
||||
case STENCIL_VALUE_KEEP:
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE);
|
||||
@@ -1332,7 +1339,7 @@ static void ConvertStencilFunc5551(GenericStencilFuncState &state) {
|
||||
}
|
||||
|
||||
void ConvertStencilFuncState(GenericStencilFuncState &state) {
|
||||
state.enabled = gstate.isStencilTestEnabled() && !g_Config.bDisableStencilTest;
|
||||
state.enabled = gstate.isStencilTestEnabled();
|
||||
if (!state.enabled)
|
||||
return;
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ bool IsColorTestAgainstZero();
|
||||
bool IsColorTestTriviallyTrue();
|
||||
bool IsAlphaTestAgainstZero();
|
||||
bool NeedsTestDiscard();
|
||||
bool IsStencilTestOutputDisabled();
|
||||
|
||||
StencilValueType ReplaceAlphaWithStencilType();
|
||||
ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend);
|
||||
@@ -71,7 +72,7 @@ struct ViewportAndScissor {
|
||||
bool dirtyDepth;
|
||||
};
|
||||
void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out);
|
||||
float ToScaledDepth(u16 z);
|
||||
float ToScaledDepthFromIntegerScale(float z);
|
||||
float FromScaledDepth(float z);
|
||||
float DepthSliceFactor();
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ void IndexGenerator::AddList(int numVerts, bool clockwise) {
|
||||
count_ += numVerts;
|
||||
prim_ = GE_PRIM_TRIANGLES;
|
||||
seenPrims_ |= 1 << GE_PRIM_TRIANGLES;
|
||||
if (!clockwise) {
|
||||
// Make sure we don't treat this as pure.
|
||||
seenPrims_ |= 1 << GE_PRIM_TRIANGLE_STRIP;
|
||||
}
|
||||
}
|
||||
|
||||
void IndexGenerator::AddStrip(int numVerts, bool clockwise) {
|
||||
@@ -96,7 +100,7 @@ void IndexGenerator::AddStrip(int numVerts, bool clockwise) {
|
||||
if (numTris > 0)
|
||||
count_ += numTris * 3;
|
||||
// This is so we can detect one single strip by just looking at seenPrims_.
|
||||
if (!seenPrims_) {
|
||||
if (!seenPrims_ && clockwise) {
|
||||
seenPrims_ = 1 << GE_PRIM_TRIANGLE_STRIP;
|
||||
prim_ = GE_PRIM_TRIANGLE_STRIP;
|
||||
pureCount_ = numVerts;
|
||||
@@ -123,6 +127,10 @@ void IndexGenerator::AddFan(int numVerts, bool clockwise) {
|
||||
count_ += numTris * 3;
|
||||
prim_ = GE_PRIM_TRIANGLES;
|
||||
seenPrims_ |= 1 << GE_PRIM_TRIANGLE_FAN;
|
||||
if (!clockwise) {
|
||||
// Make sure we don't treat this as pure.
|
||||
seenPrims_ |= 1 << GE_PRIM_TRIANGLE_STRIP;
|
||||
}
|
||||
}
|
||||
|
||||
//Lines
|
||||
@@ -218,7 +226,7 @@ void IndexGenerator::TranslateList(int numInds, const ITypeLE *inds, int indexOf
|
||||
indexOffset = index_ - indexOffset;
|
||||
// We only bother doing this minor optimization in triangle list, since it's by far the most
|
||||
// common operation that can benefit.
|
||||
if (sizeof(ITypeLE) == sizeof(inds_[0]) && indexOffset == 0) {
|
||||
if (sizeof(ITypeLE) == sizeof(inds_[0]) && indexOffset == 0 && clockwise) {
|
||||
memcpy(inds_, inds, numInds * sizeof(ITypeLE));
|
||||
inds_ += numInds;
|
||||
count_ += numInds;
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Draw {
|
||||
class DrawContext;
|
||||
}
|
||||
|
||||
enum ShaderLanguage {
|
||||
GLSL_140,
|
||||
GLSL_300,
|
||||
@@ -117,10 +121,13 @@ enum : uint64_t {
|
||||
|
||||
class ShaderManagerCommon {
|
||||
public:
|
||||
ShaderManagerCommon() {}
|
||||
ShaderManagerCommon(Draw::DrawContext *draw) : draw_(draw) {}
|
||||
virtual ~ShaderManagerCommon() {}
|
||||
|
||||
virtual void DirtyLastShader() = 0;
|
||||
|
||||
protected:
|
||||
Draw::DrawContext *draw_ = nullptr;
|
||||
};
|
||||
|
||||
struct TBuiltInResource;
|
||||
|
||||
+19
-12
@@ -1,6 +1,7 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
@@ -60,7 +61,7 @@ std::string VertexShaderDesc(const ShaderID &id) {
|
||||
}
|
||||
|
||||
void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) {
|
||||
bool isModeThrough = gstate.isModeThrough();
|
||||
bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
|
||||
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
|
||||
bool doTextureTransform = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
|
||||
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
|
||||
@@ -72,6 +73,7 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform)
|
||||
|
||||
bool doBezier = gstate_c.bezier;
|
||||
bool doSpline = gstate_c.spline;
|
||||
// These are the original vertType's values (normalized will always have colors, etc.)
|
||||
bool hasColorTess = (gstate.vertType & GE_VTYPE_COL_MASK) != 0 && (doBezier || doSpline);
|
||||
bool hasTexcoordTess = (gstate.vertType & GE_VTYPE_TC_MASK) != 0 && (doBezier || doSpline);
|
||||
bool hasNormalTess = (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 && (doBezier || doSpline);
|
||||
@@ -115,18 +117,15 @@ void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform)
|
||||
id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);
|
||||
}
|
||||
|
||||
// Okay, d[1] coming up. ==============
|
||||
if (gstate.isLightingEnabled() || doShadeMapping) {
|
||||
// doShadeMapping is stored as UVGenMode, so this is enough for isLightingEnabled.
|
||||
if (gstate.isLightingEnabled()) {
|
||||
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7);
|
||||
id.SetBit(VS_BIT_LIGHTING_ENABLE);
|
||||
}
|
||||
if (gstate.isLightingEnabled()) {
|
||||
// doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping.
|
||||
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7);
|
||||
id.SetBit(VS_BIT_LIGHTING_ENABLE);
|
||||
// Light bits
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bool chanEnabled = gstate.isLightChanEnabled(i) != 0 && gstate.isLightingEnabled();
|
||||
bool chanEnabled = gstate.isLightChanEnabled(i) != 0;
|
||||
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);
|
||||
if (chanEnabled || (doShadeMapping && (gstate.getUVLS0() == i || gstate.getUVLS1() == i))) {
|
||||
if (chanEnabled) {
|
||||
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
|
||||
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
|
||||
}
|
||||
@@ -201,8 +200,10 @@ std::string FragmentShaderDesc(const ShaderID &id) {
|
||||
case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break;
|
||||
case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break;
|
||||
case STENCIL_VALUE_DECR_8: desc << "StenDecr4 "; break;
|
||||
default: desc << "StenUnknown"; break;
|
||||
default: desc << "StenUnknown "; break;
|
||||
}
|
||||
} else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
|
||||
desc << "StenOff ";
|
||||
}
|
||||
if (id.Bit(FS_BIT_DO_TEXTURE)) {
|
||||
switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
|
||||
@@ -225,7 +226,7 @@ std::string FragmentShaderDesc(const ShaderID &id) {
|
||||
|
||||
// Here we must take all the bits of the gstate that determine what the fragment shader will
|
||||
// look like, and concatenate them together into an ID.
|
||||
void ComputeFragmentShaderID(ShaderID *id_out) {
|
||||
void ComputeFragmentShaderID(ShaderID *id_out, const Draw::Bugs &bugs) {
|
||||
ShaderID id;
|
||||
if (gstate.isModeClear()) {
|
||||
// We only need one clear shader, so let's ignore the rest of the bits.
|
||||
@@ -309,6 +310,12 @@ void ComputeFragmentShaderID(ShaderID *id_out) {
|
||||
id.SetBit(FS_BIT_FLATSHADE, doFlatShading);
|
||||
|
||||
id.SetBit(FS_BIT_SHADER_DEPAL, useShaderDepal);
|
||||
|
||||
if (g_Config.bVendorBugChecksEnabled) {
|
||||
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
|
||||
id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*id_out = id;
|
||||
|
||||
@@ -87,7 +87,8 @@ enum {
|
||||
FS_BIT_FLATSHADE = 46,
|
||||
FS_BIT_BGRA_TEXTURE = 47,
|
||||
FS_BIT_TEST_DISCARD_TO_ZERO = 48,
|
||||
// 49+ are free.
|
||||
FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL = 49,
|
||||
// 50+ are free.
|
||||
};
|
||||
|
||||
struct ShaderID {
|
||||
@@ -175,12 +176,15 @@ struct FShaderID : ShaderID {
|
||||
}
|
||||
};
|
||||
|
||||
namespace Draw {
|
||||
class Bugs;
|
||||
}
|
||||
|
||||
|
||||
bool CanUseHardwareTransform(int prim);
|
||||
void ComputeVertexShaderID(ShaderID *id, uint32_t vertexType, bool useHWTransform);
|
||||
// Generates a compact string that describes the shader. Useful in a list to get an overview
|
||||
// of the current flora of shaders.
|
||||
std::string VertexShaderDesc(const ShaderID &id);
|
||||
|
||||
void ComputeFragmentShaderID(ShaderID *id);
|
||||
void ComputeFragmentShaderID(ShaderID *id, const Draw::Bugs &bugs);
|
||||
std::string FragmentShaderDesc(const ShaderID &id);
|
||||
@@ -42,9 +42,27 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo
|
||||
return (pspViewport - gstate_c.vpYOffset) * heightScale;
|
||||
};
|
||||
auto reverseViewportZ = [hasNegZ](float z) {
|
||||
float pspViewport = (z - gstate.getViewportZCenter()) * (1.0f / gstate.getViewportZScale());
|
||||
// Differs from GLES: depth is 0 to 1, not -1 to 1.
|
||||
float realViewport = (pspViewport - gstate_c.vpZOffset) * gstate_c.vpDepthScale;
|
||||
float vpZScale = gstate.getViewportZScale();
|
||||
float vpZCenter = gstate.getViewportZCenter();
|
||||
|
||||
float scale, center;
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) {
|
||||
// These are just the reverse of the formulas in GPUStateUtils.
|
||||
float halfActualZRange = vpZScale * (1.0f / gstate_c.vpDepthScale);
|
||||
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
|
||||
|
||||
// In accurate depth mode, we're comparing against a value scaled to (minz, maxz).
|
||||
// And minz might be very negative, (e.g. if we're clamping in that direction.)
|
||||
scale = halfActualZRange;
|
||||
center = minz + halfActualZRange;
|
||||
} else {
|
||||
// In old-style depth mode, we're comparing against a value scaled to viewport.
|
||||
// (and possibly incorrectly clipped against it.)
|
||||
scale = vpZScale;
|
||||
center = vpZCenter;
|
||||
}
|
||||
|
||||
float realViewport = (z - center) * (1.0f / scale);
|
||||
return hasNegZ ? realViewport : (realViewport * 0.5f + 0.5f);
|
||||
};
|
||||
auto sortPair = [](float a, float b) {
|
||||
|
||||
@@ -191,9 +191,9 @@ void SoftwareTransform(
|
||||
fog_slope = std::signbit(fog_slope) ? -65535.0f : 65535.0f;
|
||||
}
|
||||
|
||||
int colorIndOffset = 0;
|
||||
int provokeIndOffset = 0;
|
||||
if (params->provokeFlatFirst) {
|
||||
colorIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear());
|
||||
provokeIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear());
|
||||
}
|
||||
|
||||
VertexReader reader(decoded, decVtxFormat, vertType);
|
||||
@@ -206,8 +206,8 @@ void SoftwareTransform(
|
||||
reader.ReadPos(vert.pos);
|
||||
|
||||
if (reader.hasColor0()) {
|
||||
if (colorIndOffset != 0 && index + colorIndOffset < maxIndex) {
|
||||
reader.Goto(index + colorIndOffset);
|
||||
if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) {
|
||||
reader.Goto(index + provokeIndOffset);
|
||||
reader.ReadColor0_8888(vert.color0);
|
||||
reader.Goto(index);
|
||||
} else {
|
||||
@@ -247,10 +247,24 @@ void SoftwareTransform(
|
||||
Vec3f worldnormal(0, 0, 1);
|
||||
reader.ReadPos(pos);
|
||||
|
||||
float ruv[2] = { 0.0f, 0.0f };
|
||||
if (reader.hasUV())
|
||||
reader.ReadUV(ruv);
|
||||
|
||||
// Read all the provoking vertex values here.
|
||||
Vec4f unlitColor;
|
||||
if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex)
|
||||
reader.Goto(index + provokeIndOffset);
|
||||
if (reader.hasColor0())
|
||||
reader.ReadColor0(unlitColor.AsArray());
|
||||
else
|
||||
unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA());
|
||||
if (reader.hasNormal())
|
||||
reader.ReadNrm(normal.AsArray());
|
||||
|
||||
if (!skinningEnabled) {
|
||||
Vec3ByMatrix43(out, pos, gstate.worldMatrix);
|
||||
if (reader.hasNormal()) {
|
||||
reader.ReadNrm(normal.AsArray());
|
||||
if (gstate.areNormalsReversed()) {
|
||||
normal = -normal;
|
||||
}
|
||||
@@ -259,9 +273,9 @@ void SoftwareTransform(
|
||||
}
|
||||
} else {
|
||||
float weights[8];
|
||||
// TODO: For flat, are weights from the provoking used for color/normal?
|
||||
reader.Goto(index);
|
||||
reader.ReadWeights(weights);
|
||||
if (reader.hasNormal())
|
||||
reader.ReadNrm(normal.AsArray());
|
||||
|
||||
// Skinning
|
||||
Vec3f psum(0, 0, 0);
|
||||
@@ -291,20 +305,7 @@ void SoftwareTransform(
|
||||
}
|
||||
}
|
||||
|
||||
// Perform lighting here if enabled. don't need to check through, it's checked above.
|
||||
Vec4f unlitColor = Vec4f(1, 1, 1, 1);
|
||||
if (reader.hasColor0()) {
|
||||
if (colorIndOffset != 0 && index + colorIndOffset < maxIndex) {
|
||||
reader.Goto(index + colorIndOffset);
|
||||
reader.ReadColor0(&unlitColor.x);
|
||||
reader.Goto(index);
|
||||
} else {
|
||||
reader.ReadColor0(&unlitColor.x);
|
||||
}
|
||||
} else {
|
||||
unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA());
|
||||
}
|
||||
|
||||
// Perform lighting here if enabled.
|
||||
if (gstate.isLightingEnabled()) {
|
||||
float litColor0[4];
|
||||
float litColor1[4];
|
||||
@@ -338,10 +339,6 @@ void SoftwareTransform(
|
||||
}
|
||||
}
|
||||
|
||||
float ruv[2] = {0.0f, 0.0f};
|
||||
if (reader.hasUV())
|
||||
reader.ReadUV(ruv);
|
||||
|
||||
// Perform texture coordinate generation after the transform and lighting - one style of UV depends on lights.
|
||||
switch (gstate.getUVGenMode()) {
|
||||
case GE_TEXMAP_TEXTURE_COORDS: // UV mapping
|
||||
@@ -354,6 +351,8 @@ void SoftwareTransform(
|
||||
|
||||
case GE_TEXMAP_TEXTURE_MATRIX:
|
||||
{
|
||||
// TODO: What's the correct behavior with flat shading? Provoked normal or real normal?
|
||||
|
||||
// Projection mapping
|
||||
Vec3f source;
|
||||
switch (gstate.getUVProjMode()) {
|
||||
@@ -391,8 +390,23 @@ void SoftwareTransform(
|
||||
case GE_TEXMAP_ENVIRONMENT_MAP:
|
||||
// Shade mapping - use two light sources to generate U and V.
|
||||
{
|
||||
Vec3f lightpos0 = Vec3f(&lighter.lpos[gstate.getUVLS0() * 3]).Normalized();
|
||||
Vec3f lightpos1 = Vec3f(&lighter.lpos[gstate.getUVLS1() * 3]).Normalized();
|
||||
auto getLPosFloat = [&](int l, int i) {
|
||||
return getFloat24(gstate.lpos[l * 3 + i]);
|
||||
};
|
||||
auto getLPos = [&](int l) {
|
||||
return Vec3f(getLPosFloat(l, 0), getLPosFloat(l, 1), getLPosFloat(l, 2));
|
||||
};
|
||||
auto calcShadingLPos = [&](int l) {
|
||||
Vec3f pos = getLPos(l);
|
||||
if (pos.Length2() == 0.0f) {
|
||||
return Vec3f(0.0f, 0.0f, 1.0f);
|
||||
} else {
|
||||
return pos.Normalized();
|
||||
}
|
||||
};
|
||||
// Might not have lighting enabled, so don't use lighter.
|
||||
Vec3f lightpos0 = calcShadingLPos(gstate.getUVLS0());
|
||||
Vec3f lightpos1 = calcShadingLPos(gstate.getUVLS1());
|
||||
|
||||
uv[0] = (1.0f + Dot(lightpos0, worldnormal))/2.0f;
|
||||
uv[1] = (1.0f + Dot(lightpos1, worldnormal))/2.0f;
|
||||
@@ -446,7 +460,7 @@ void SoftwareTransform(
|
||||
if (params->allowSeparateAlphaClear || (alphaMatchesColor && depthMatchesStencil)) {
|
||||
result->color = transformed[1].color0_32;
|
||||
// Need to rescale from a [0, 1] float. This is the final transformed value.
|
||||
result->depth = ToScaledDepth((s16)(int)(transformed[1].z * 65535.0f));
|
||||
result->depth = ToScaledDepthFromIntegerScale((int)(transformed[1].z * 65535.0f));
|
||||
result->action = SW_CLEAR;
|
||||
gpuStats.numClears++;
|
||||
return;
|
||||
|
||||
+23
-102
@@ -488,106 +488,23 @@ void DrawEngineCommon::ClearSplineBezierWeights() {
|
||||
Spline3DWeight::weightsCache.Clear();
|
||||
}
|
||||
|
||||
void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) {
|
||||
PROFILE_THIS_SCOPE("spline");
|
||||
DispatchFlush();
|
||||
// Specialize to make instance (to avoid link error).
|
||||
template void DrawEngineCommon::SubmitCurve<BezierSurface>(const void *control_points, const void *indices, BezierSurface &surface, u32 vertType, int *bytesRead, const char *scope);
|
||||
template void DrawEngineCommon::SubmitCurve<SplineSurface>(const void *control_points, const void *indices, SplineSurface &surface, u32 vertType, int *bytesRead, const char *scope);
|
||||
|
||||
// Real hardware seems to draw nothing when given < 4 either U or V.
|
||||
if (count_u < 4 || count_v < 4)
|
||||
return;
|
||||
|
||||
SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE / 2);
|
||||
|
||||
int num_points = count_u * count_v;
|
||||
u16 index_lower_bound = 0;
|
||||
u16 index_upper_bound = num_points - 1;
|
||||
IndexConverter ConvertIndex(vertType, indices);
|
||||
if (indices)
|
||||
GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound);
|
||||
|
||||
VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24));
|
||||
*bytesRead = num_points * origVDecoder->VertexSize();
|
||||
|
||||
// Simplify away bones and morph before proceeding
|
||||
SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1));
|
||||
u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points);
|
||||
|
||||
u32 origVertType = vertType;
|
||||
vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType);
|
||||
|
||||
VertexDecoder *vdecoder = GetVertexDecoder(vertType);
|
||||
|
||||
int vertexSize = vdecoder->VertexSize();
|
||||
if (vertexSize != sizeof(SimpleVertex)) {
|
||||
ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex));
|
||||
}
|
||||
|
||||
// Make an array of pointers to the control points, to get rid of indices.
|
||||
const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points);
|
||||
for (int idx = 0; idx < num_points; idx++)
|
||||
points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx);
|
||||
|
||||
OutputBuffers output;
|
||||
output.vertices = (SimpleVertex *)(decoded + DECODED_VERTEX_BUFFER_SIZE / 2);
|
||||
output.indices = decIndex;
|
||||
output.count = 0;
|
||||
|
||||
SplineSurface surface;
|
||||
surface.tess_u = tess_u;
|
||||
surface.tess_v = tess_v;
|
||||
surface.type_u = type_u;
|
||||
surface.type_v = type_v;
|
||||
surface.num_points_u = count_u;
|
||||
surface.num_points_v = count_v;
|
||||
surface.num_patches_u = count_u - 3;
|
||||
surface.num_patches_v = count_v - 3;
|
||||
surface.primType = prim_type;
|
||||
surface.patchFacing = patchFacing;
|
||||
surface.Init(DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize);
|
||||
|
||||
if (CanUseHardwareTessellation(prim_type)) {
|
||||
HardwareTessellation(output, surface, origVertType, points, tessDataTransfer);
|
||||
} else {
|
||||
ControlPoints cpoints(points, num_points, managedBuf);
|
||||
SoftwareTessellation(output, surface, origVertType, cpoints);
|
||||
}
|
||||
|
||||
u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
|
||||
|
||||
UVScale prevUVScale;
|
||||
if ((origVertType & GE_VTYPE_TC_MASK) != 0) {
|
||||
// We scaled during Normalize already so let's turn it off when drawing.
|
||||
prevUVScale = gstate_c.uv;
|
||||
gstate_c.uv.uScale = 1.0f;
|
||||
gstate_c.uv.vScale = 1.0f;
|
||||
gstate_c.uv.uOff = 0.0f;
|
||||
gstate_c.uv.vOff = 0.0f;
|
||||
}
|
||||
|
||||
uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode());
|
||||
|
||||
int generatedBytesRead;
|
||||
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(prim_type), output.count, vertTypeID, &generatedBytesRead);
|
||||
|
||||
DispatchFlush();
|
||||
|
||||
if ((origVertType & GE_VTYPE_TC_MASK) != 0) {
|
||||
gstate_c.uv = prevUVScale;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead) {
|
||||
PROFILE_THIS_SCOPE("bezier");
|
||||
template<class Surface>
|
||||
void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indices, Surface &surface, u32 vertType, int *bytesRead, const char *scope) {
|
||||
PROFILE_THIS_SCOPE(scope);
|
||||
DispatchFlush();
|
||||
|
||||
// Real hardware seems to draw nothing when given < 4 either U or V.
|
||||
// This would result in num_patches_u / num_patches_v being 0.
|
||||
if (count_u < 4 || count_v < 4)
|
||||
if (surface.num_points_u < 4 || surface.num_points_v < 4)
|
||||
return;
|
||||
|
||||
SimpleBufferManager managedBuf(decoded, DECODED_VERTEX_BUFFER_SIZE / 2);
|
||||
|
||||
int num_points = count_u * count_v;
|
||||
int num_points = surface.num_points_u * surface.num_points_v;
|
||||
u16 index_lower_bound = 0;
|
||||
u16 index_upper_bound = num_points - 1;
|
||||
IndexConverter ConvertIndex(vertType, indices);
|
||||
@@ -600,7 +517,16 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
||||
// Simplify away bones and morph before proceeding
|
||||
// There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great.
|
||||
SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1));
|
||||
if (!simplified_control_points) {
|
||||
ERROR_LOG(G3D, "Failed to allocate space for simplified control points, skipping curve draw");
|
||||
return;
|
||||
}
|
||||
|
||||
u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points);
|
||||
if (!temp_buffer) {
|
||||
ERROR_LOG(G3D, "Failed to allocate space for temp buffer, skipping curve draw");
|
||||
return;
|
||||
}
|
||||
|
||||
u32 origVertType = vertType;
|
||||
vertType = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertType);
|
||||
@@ -614,6 +540,10 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
||||
|
||||
// Make an array of pointers to the control points, to get rid of indices.
|
||||
const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points);
|
||||
if (!points) {
|
||||
ERROR_LOG(G3D, "Failed to allocate space for control point pointers, skipping curve draw");
|
||||
return;
|
||||
}
|
||||
for (int idx = 0; idx < num_points; idx++)
|
||||
points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx);
|
||||
|
||||
@@ -622,18 +552,9 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
||||
output.indices = decIndex;
|
||||
output.count = 0;
|
||||
|
||||
BezierSurface surface;
|
||||
surface.tess_u = tess_u;
|
||||
surface.tess_v = tess_v;
|
||||
surface.num_points_u = count_u;
|
||||
surface.num_points_v = count_v;
|
||||
surface.num_patches_u = (count_u - 1) / 3;
|
||||
surface.num_patches_v = (count_v - 1) / 3;
|
||||
surface.primType = prim_type;
|
||||
surface.patchFacing = patchFacing;
|
||||
surface.Init(DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize);
|
||||
|
||||
if (CanUseHardwareTessellation(prim_type)) {
|
||||
if (CanUseHardwareTessellation(surface.primType)) {
|
||||
HardwareTessellation(output, surface, origVertType, points, tessDataTransfer);
|
||||
} else {
|
||||
ControlPoints cpoints(points, num_points, managedBuf);
|
||||
@@ -654,7 +575,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
||||
|
||||
uint32_t vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode());
|
||||
int generatedBytesRead;
|
||||
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(prim_type), output.count, vertTypeID, &generatedBytesRead);
|
||||
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, gstate.getCullMode(), &generatedBytesRead);
|
||||
|
||||
DispatchFlush();
|
||||
|
||||
|
||||
@@ -642,9 +642,10 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c
|
||||
}
|
||||
|
||||
void TextureCacheCommon::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg) {
|
||||
// Must be in VRAM so | 0x04000000 it is. Also, ignore memory mirrors.
|
||||
// Mask to ignore the Z memory mirrors if the address is in VRAM.
|
||||
// These checks are mainly to reduce scanning all textures.
|
||||
const u32 addr = (address | 0x04000000) & 0x3F9FFFFF;
|
||||
const u32 mirrorMask = 0x00600000;
|
||||
const u32 addr = Memory::IsVRAMAddress(address) ? (address & ~mirrorMask) : address;
|
||||
const u32 bpp = framebuffer->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
const u64 cacheKey = (u64)addr << 32;
|
||||
// If it has a clut, those are the low 32 bits, so it'll be inside this range.
|
||||
@@ -756,10 +757,13 @@ bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, Vi
|
||||
|
||||
AttachedFramebufferInfo fbInfo = { 0 };
|
||||
|
||||
const u64 mirrorMask = 0x00600000;
|
||||
// Must be in VRAM so | 0x04000000 it is. Also, ignore memory mirrors.
|
||||
const u32 addr = (address | 0x04000000) & 0x3FFFFFFF & ~mirrorMask;
|
||||
const u32 texaddr = ((entry->addr + texaddrOffset) & ~mirrorMask);
|
||||
const u32 mirrorMask = 0x00600000;
|
||||
u32 addr = address & 0x3FFFFFFF;
|
||||
u32 texaddr = entry->addr + texaddrOffset;
|
||||
if (entry->addr & 0x04000000) {
|
||||
addr &= ~mirrorMask;
|
||||
texaddr &= ~mirrorMask;
|
||||
}
|
||||
const bool noOffset = texaddr == addr;
|
||||
const bool exactMatch = noOffset && entry->format < 4;
|
||||
const u32 w = 1 << ((entry->dim >> 0) & 0xf);
|
||||
@@ -1002,7 +1006,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) {
|
||||
clutRenderOffset_ = MAX_CLUT_OFFSET;
|
||||
for (size_t i = 0, n = fbCache_.size(); i < n; ++i) {
|
||||
auto framebuffer = fbCache_[i];
|
||||
const u32 fb_address = framebuffer->fb_address | 0x04000000;
|
||||
const u32 fb_address = framebuffer->fb_address & 0x3FFFFFFF;
|
||||
const u32 bpp = framebuffer->drawnFormat == GE_FORMAT_8888 ? 4 : 2;
|
||||
u32 offset = clutFramebufAddr - fb_address;
|
||||
|
||||
|
||||
@@ -348,41 +348,36 @@ static inline u32 makecol(int r, int g, int b, int a) {
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
static inline int mul_3_8(int c) {
|
||||
// This is 3/8 * c = 4/8 * c - 1/8 * c.
|
||||
return (c >> 1) - (c >> 3);
|
||||
static inline int mix_2_3(int c1, int c2) {
|
||||
return (c1 + c1 + c2) / 3;
|
||||
}
|
||||
|
||||
// This could probably be done faster by decoding two or four blocks at a time with SSE/NEON.
|
||||
void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) {
|
||||
u16 c1 = src->color1;
|
||||
u16 c2 = src->color2;
|
||||
int red1 = Convert5To8(c1 & 0x1F);
|
||||
int red2 = Convert5To8(c2 & 0x1F);
|
||||
int green1 = Convert6To8((c1 >> 5) & 0x3F);
|
||||
int green2 = Convert6To8((c2 >> 5) & 0x3F);
|
||||
int blue1 = Convert5To8((c1 >> 11) & 0x1F);
|
||||
int blue2 = Convert5To8((c2 >> 11) & 0x1F);
|
||||
int red1 = (c1 << 3) & 0xF8;
|
||||
int red2 = (c2 << 3) & 0xF8;
|
||||
int green1 = (c1 >> 3) & 0xFC;
|
||||
int green2 = (c2 >> 3) & 0xFC;
|
||||
int blue1 = (c1 >> 8) & 0xF8;
|
||||
int blue2 = (c2 >> 8) & 0xF8;
|
||||
|
||||
// Keep alpha zero for non-DXT1 to skip masking the colors.
|
||||
int alpha = ignore1bitAlpha ? 0 : 255;
|
||||
|
||||
colors_[0] = makecol(red1, green1, blue1, alpha);
|
||||
colors_[1] = makecol(red2, green2, blue2, alpha);
|
||||
if (c1 > c2 || ignore1bitAlpha) {
|
||||
int red3 = mul_3_8(red2 - red1);
|
||||
int green3 = mul_3_8(green2 - green1);
|
||||
int blue3 = mul_3_8(blue2 - blue1);
|
||||
colors_[2] = makecol(red1 + red3, green1 + green3, blue1 + blue3, alpha);
|
||||
colors_[3] = makecol(red2 - red3, green2 - green3, blue2 - blue3, alpha);
|
||||
if (c1 > c2) {
|
||||
colors_[2] = makecol(mix_2_3(red1, red2), mix_2_3(green1, green2), mix_2_3(blue1, blue2), alpha);
|
||||
colors_[3] = makecol(mix_2_3(red2, red1), mix_2_3(green2, green1), mix_2_3(blue2, blue1), alpha);
|
||||
} else {
|
||||
// Average
|
||||
int red3 = (red1 + red2 + 1) / 2;
|
||||
int green3 = (green1 + green2 + 1) / 2;
|
||||
int blue3 = (blue1 + blue2 + 1) / 2;
|
||||
colors_[2] = makecol(red3, green3, blue3, 255);
|
||||
// Color2 but transparent
|
||||
colors_[3] = makecol(red2, green2, blue2, 0);
|
||||
// Average - these are always left shifted, so no need to worry about ties.
|
||||
int red3 = (red1 + red2) / 2;
|
||||
int green3 = (green1 + green2) / 2;
|
||||
int blue3 = (blue1 + blue2) / 2;
|
||||
colors_[2] = makecol(red3, green3, blue3, alpha);
|
||||
colors_[3] = makecol(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,13 +385,13 @@ static inline u8 lerp8(const DXT5Block *src, int n) {
|
||||
// These weights translate alpha1/alpha2 to fixed 8.8 point, pre-divided by 7.
|
||||
int weight1 = ((7 - n) << 8) / 7;
|
||||
int weight2 = (n << 8) / 7;
|
||||
return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2) >> 8);
|
||||
return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2 + 255) >> 8);
|
||||
}
|
||||
|
||||
static inline u8 lerp6(const DXT5Block *src, int n) {
|
||||
int weight1 = ((5 - n) << 8) / 5;
|
||||
int weight2 = (n << 8) / 5;
|
||||
return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2) >> 8);
|
||||
return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2 + 255) >> 8);
|
||||
}
|
||||
|
||||
void DXTDecoder::DecodeAlphaDXT5(const DXT5Block *src) {
|
||||
@@ -436,8 +431,7 @@ void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int
|
||||
int colordata = src->color.lines[y];
|
||||
u32 alphadata = src->alphaLines[y];
|
||||
for (int x = 0; x < 4; x++) {
|
||||
const u8 a4 = alphadata & 0xF;
|
||||
dst[x] = colors_[colordata & 3] | (a4 << 24) | (a4 << 28);
|
||||
dst[x] = colors_[colordata & 3] | (alphadata << 28);
|
||||
colordata >>= 2;
|
||||
alphadata >>= 4;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32
|
||||
#define DoReliableHash32 XXH32
|
||||
#define DoReliableHash64 XXH64
|
||||
|
||||
#ifdef _M_X64
|
||||
#if defined(_M_X64) || defined(ARM64)
|
||||
#define DoReliableHash XXH64
|
||||
typedef u64 ReliableHashType;
|
||||
#else
|
||||
@@ -58,7 +58,7 @@ typedef u32 ReliableHashType;
|
||||
#endif
|
||||
|
||||
// For ARM64, NEON is mandatory, so we also statically link.
|
||||
#elif PPSSPP_ARCH(ARM64)
|
||||
#elif PPSSPP_ARCH(ARM64) || defined(ARM64)
|
||||
#define DoQuickTexHash QuickTexHashNEON
|
||||
#define StableQuickTexHash QuickTexHashNEON
|
||||
#define DoUnswizzleTex16 DoUnswizzleTex16NEON
|
||||
|
||||
@@ -107,9 +107,9 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
|
||||
Vec3f lightDir(0, 0, 0);
|
||||
|
||||
if (type == GE_LIGHTTYPE_DIRECTIONAL)
|
||||
toLight = Vec3f(&lpos[l * 3]); // lightdir is for spotlights
|
||||
toLight = Vec3Packedf(&lpos[l * 3]); // lightdir is for spotlights
|
||||
else
|
||||
toLight = Vec3f(&lpos[l * 3]) - pos;
|
||||
toLight = Vec3Packedf(&lpos[l * 3]) - pos;
|
||||
|
||||
bool doSpecular = gstate.isUsingSpecularLight(l);
|
||||
bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(l);
|
||||
@@ -139,7 +139,7 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
|
||||
break;
|
||||
case GE_LIGHTTYPE_SPOT:
|
||||
case GE_LIGHTTYPE_UNKNOWN:
|
||||
lightDir = Vec3f(&ldir[l * 3]);
|
||||
lightDir = Vec3Packedf(&ldir[l * 3]);
|
||||
angle = Dot(toLight.Normalized(), lightDir.Normalized());
|
||||
if (angle >= lcutoff[l])
|
||||
lightScale = clamp(1.0f / (latt[l * 3] + latt[l * 3 + 1] * distanceToLight + latt[l * 3 + 2] * distanceToLight*distanceToLight), 0.0f, 1.0f) * powf(angle, lconv[l]);
|
||||
|
||||
@@ -33,21 +33,22 @@
|
||||
#define SHADERLOG
|
||||
#endif
|
||||
|
||||
static const char *depalVShaderHLSL =
|
||||
"struct VS_IN {\n"
|
||||
" float3 a_position : POSITION;\n"
|
||||
" float2 a_texcoord0 : TEXCOORD0;\n"
|
||||
"};\n"
|
||||
"struct VS_OUT {\n"
|
||||
" float2 Texcoord : TEXCOORD0;\n"
|
||||
" float4 Position : SV_Position;\n"
|
||||
"};\n"
|
||||
"VS_OUT main(VS_IN input) {\n"
|
||||
" VS_OUT output;\n"
|
||||
" output.Texcoord = input.a_texcoord0;\n"
|
||||
" output.Position = float4(input.a_position, 1.0);\n"
|
||||
" return output;\n"
|
||||
"}\n";
|
||||
static const char *depalVShaderHLSL = R"(
|
||||
struct VS_IN {
|
||||
float3 a_position : POSITION;
|
||||
float2 a_texcoord0 : TEXCOORD0;
|
||||
};
|
||||
struct VS_OUT {
|
||||
float2 Texcoord : TEXCOORD0;
|
||||
float4 Position : SV_Position;
|
||||
};
|
||||
VS_OUT main(VS_IN input) {
|
||||
VS_OUT output;
|
||||
output.Texcoord = input.a_texcoord0;
|
||||
output.Position = float4(input.a_position, 1.0);
|
||||
return output;
|
||||
}
|
||||
)";
|
||||
|
||||
static const D3D11_INPUT_ELEMENT_DESC g_DepalVertexElements[] = {
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, },
|
||||
|
||||
@@ -137,6 +137,8 @@ void DrawEngineD3D11::DestroyDeviceObjects() {
|
||||
ClearTrackedVertexArrays();
|
||||
ClearInputLayoutMap();
|
||||
delete tessDataTransferD3D11;
|
||||
tessDataTransferD3D11 = nullptr;
|
||||
tessDataTransfer = nullptr;
|
||||
delete pushVerts_;
|
||||
delete pushInds_;
|
||||
depthStencilCache_.Iterate([&](const uint64_t &key, ID3D11DepthStencilState *ds) {
|
||||
@@ -655,7 +657,7 @@ rotateVBO:
|
||||
int scissorX2 = gstate.getScissorX2() + 1;
|
||||
int scissorY2 = gstate.getScissorY2() + 1;
|
||||
framebufferManager_->SetSafeSize(scissorX2, scissorY2);
|
||||
if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) {
|
||||
if ((gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) {
|
||||
int scissorX1 = gstate.getScissorX1();
|
||||
int scissorY1 = gstate.getScissorY1();
|
||||
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);
|
||||
|
||||
@@ -512,9 +512,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) {
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
|
||||
if (g_Config.bDisableSlowFramebufEffects) {
|
||||
return;
|
||||
}
|
||||
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
|
||||
bool matchingSize = src->width == dst->width && src->height == dst->height;
|
||||
bool matchingRenderSize = src->renderWidth == dst->renderWidth && src->renderHeight == dst->renderHeight;
|
||||
@@ -537,7 +534,7 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr
|
||||
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
|
||||
// Let's just not bother with the copy in that case.
|
||||
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
|
||||
if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) {
|
||||
if (GPUStepping::IsStepping()) {
|
||||
skipCopy = true;
|
||||
}
|
||||
// Currently rendering to this framebuffer. Need to make a copy.
|
||||
@@ -553,7 +550,7 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr
|
||||
} else {
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
|
||||
}
|
||||
} else if (framebuffer != currentRenderVfb_) {
|
||||
} else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) {
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
ERROR_LOG_REPORT_ONCE(d3d11SelfTexture, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags);
|
||||
@@ -687,7 +684,7 @@ void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, in
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 z_address = (0x04000000) | vfb->z_address;
|
||||
const u32 z_address = vfb->z_address;
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
|
||||
stockD3D11.Create(device_);
|
||||
|
||||
shaderManagerD3D11_ = new ShaderManagerD3D11(device_, context_, featureLevel);
|
||||
shaderManagerD3D11_ = new ShaderManagerD3D11(draw, device_, context_, featureLevel);
|
||||
framebufferManagerD3D11_ = new FramebufferManagerD3D11(draw);
|
||||
framebufferManager_ = framebufferManagerD3D11_;
|
||||
textureCacheD3D11_ = new TextureCacheD3D11(draw);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "math/math_util.h"
|
||||
#include "math/dataconv.h"
|
||||
#include "file/vfs.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "util/text/utf8.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Core/Config.h"
|
||||
@@ -96,9 +97,9 @@ ShaderManagerD3D11::ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext
|
||||
memset(&ub_lights, 0, sizeof(ub_lights));
|
||||
memset(&ub_bones, 0, sizeof(ub_bones));
|
||||
|
||||
INFO_LOG(G3D, "sizeof(ub_base): %d", (int)sizeof(ub_base));
|
||||
INFO_LOG(G3D, "sizeof(ub_lights): %d", (int)sizeof(ub_lights));
|
||||
INFO_LOG(G3D, "sizeof(ub_bones): %d", (int)sizeof(ub_bones));
|
||||
static_assert(sizeof(ub_base) <= 512, "ub_base grew too big");
|
||||
static_assert(sizeof(ub_lights) <= 512, "ub_lights grew too big");
|
||||
static_assert(sizeof(ub_bones) <= 384, "ub_bones grew too big");
|
||||
|
||||
D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE };
|
||||
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_base));
|
||||
@@ -195,7 +196,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID);
|
||||
ComputeFragmentShaderID(&FSID, draw_->GetBugs());
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ class D3D11PushBuffer;
|
||||
|
||||
class ShaderManagerD3D11 : public ShaderManagerCommon {
|
||||
public:
|
||||
ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel);
|
||||
ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel);
|
||||
~ShaderManagerD3D11();
|
||||
|
||||
void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform);
|
||||
|
||||
@@ -223,7 +223,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
||||
#endif
|
||||
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
if (IsStencilTestOutputDisabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
|
||||
@@ -71,6 +71,7 @@ VS_OUT main(VS_IN In) {
|
||||
|
||||
// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass.
|
||||
bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
|
||||
addr &= 0x3FFFFFFF;
|
||||
if (!MayIntersectFramebuffer(addr)) {
|
||||
return false;
|
||||
}
|
||||
@@ -78,7 +79,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ
|
||||
VirtualFramebuffer *dstBuffer = 0;
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
VirtualFramebuffer *vfb = vfbs_[i];
|
||||
if (MaskedEqual(vfb->fb_address, addr)) {
|
||||
if (vfb->fb_address == addr) {
|
||||
dstBuffer = vfb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ public:
|
||||
};
|
||||
|
||||
TextureShaderApplierD3D11(ID3D11DeviceContext *context, ID3D11PixelShader *pshader, ID3D11Buffer *dynamicBuffer, float bufferW, float bufferH, int renderW, int renderH, float xoff, float yoff)
|
||||
: context_(context), pshader_(pshader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) {
|
||||
: context_(context), pshader_(pshader), vbuffer_(dynamicBuffer), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) {
|
||||
static const Pos pos[4] = {
|
||||
{ -1, 1, 0 },
|
||||
{ 1, 1, 0 },
|
||||
@@ -297,11 +297,6 @@ public:
|
||||
verts_[i].pos.y += yoff;
|
||||
verts_[i].uv = uv[i];
|
||||
}
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
context->Map(dynamicBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, &verts_[0], 4 * 5 * sizeof(float));
|
||||
context->Unmap(dynamicBuffer, 0);
|
||||
vbuffer_ = dynamicBuffer;
|
||||
}
|
||||
|
||||
void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff, float xoff, float yoff) {
|
||||
@@ -320,28 +315,34 @@ public:
|
||||
|
||||
const float left = u1 * invHalfWidth - 1.0f + xoff;
|
||||
const float right = u2 * invHalfWidth - 1.0f + xoff;
|
||||
const float top = v1 * invHalfHeight - 1.0f + yoff;
|
||||
const float bottom = v2 * invHalfHeight - 1.0f + yoff;
|
||||
const float top = (bufferH_ - v1) * invHalfHeight - 1.0f + yoff;
|
||||
const float bottom = (bufferH_ - v2) * invHalfHeight - 1.0f + yoff;
|
||||
|
||||
float z = 0.0f;
|
||||
// Points are: BL, BR, TL, TR.
|
||||
verts_[0].pos = Pos(left, bottom, z);
|
||||
verts_[1].pos = Pos(right, bottom, z);
|
||||
verts_[2].pos = Pos(left, top, z);
|
||||
verts_[3].pos = Pos(right, top, z);
|
||||
verts_[0].pos = Pos(left, top, z);
|
||||
verts_[1].pos = Pos(right, top, z);
|
||||
verts_[2].pos = Pos(left, bottom, z);
|
||||
verts_[3].pos = Pos(right, bottom, z);
|
||||
|
||||
// And also the UVs, same order.
|
||||
const float uvleft = u1 * invWidth;
|
||||
const float uvright = u2 * invWidth;
|
||||
const float uvtop = v1 * invHeight;
|
||||
const float uvbottom = v2 * invHeight;
|
||||
verts_[0].uv = UV(uvleft, uvbottom);
|
||||
verts_[1].uv = UV(uvright, uvbottom);
|
||||
verts_[2].uv = UV(uvleft, uvtop);
|
||||
verts_[3].uv = UV(uvright, uvtop);
|
||||
|
||||
verts_[0].uv = UV(uvleft, uvtop);
|
||||
verts_[1].uv = UV(uvright, uvtop);
|
||||
verts_[2].uv = UV(uvleft, uvbottom);
|
||||
verts_[3].uv = UV(uvright, uvbottom);
|
||||
|
||||
// We need to reapply the texture next time since we cropped UV.
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
context_->Map(vbuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, &verts_[0], 4 * 5 * sizeof(float));
|
||||
context_->Unmap(vbuffer_, 0);
|
||||
}
|
||||
|
||||
void Use(ID3D11VertexShader *vshader, ID3D11InputLayout *decl) {
|
||||
@@ -398,11 +399,11 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra
|
||||
shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset, xoff, yoff);
|
||||
shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader(), depalShaderCache_->GetInputLayout());
|
||||
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
context_->PSSetShaderResources(3, 1, &clutTexture);
|
||||
context_->PSSetSamplers(3, 1, &stockD3D11.samplerPoint2DWrap);
|
||||
framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY);
|
||||
framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF);
|
||||
context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DWrap);
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
shaderApply.Shade();
|
||||
|
||||
framebufferManagerD3D11_->RebindFramebuffer();
|
||||
|
||||
Loaded 100 of 339 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user